SqlConnection忽略用户的默认架构
本文关键字:默认 用户 SqlConnection | 更新日期: 2023-09-27 18:01:08
很抱歉这么长时间,但我看到了太多信息太少的问题。。。如果有人看到我前几行的错误,我会很高兴。。。
我有一个SQL Server 2008 R2数据库,在通过C#SqlConnection进行连接时,无法获得我认为应该正确的行为。
我有两个用Visual C#2010学习版构建的C#应用程序:
- 一个用于数据导入/导出/报告和浏览
- 一个用于做一些复杂的处理
这一切都在Windows 7上,所有更新等…
这两个应用程序中的每个应用程序使用的一些表是共享的公共表,而其他表则需要保持分离。由于我需要能够在双方之间转换和传输数据,所以我希望将所有这些都保存在一个数据库中。
为了保持一定程度的分离,我创建了两个模式、两个用户、两个角色和两个登录,比如:
CREATE LOGIN [Import_User] WITH PASSWORD=N'*****'
CREATE LOGIN [Engine_User] WITH PASSWORD=N'*****'
CREATE USER [Import_User] FOR LOGIN [Import_User] WITH DEFAULT_SCHEMA=[Import_Schema]
CREATE USER [Engine_User] FOR LOGIN [Engine_User] WITH DEFAULT_SCHEMA=[Engine_Schema]
CREATE ROLE [Import_Role] AUTHORIZATION [dbo]
CREATE ROLE [Engine_Role] AUTHORIZATION [dbo]
EXEC('CREATE SCHEMA [Import_Schema] AUTHORIZATION [Import_User]')
EXEC('CREATE SCHEMA [Engine_Schema] AUTHORIZATION [Engine_User]')
-- Import role permissions on the Import schema
GRANT EXECUTE, DELETE, INSERT, SELECT, UPDATE, REFERENCES ON SCHEMA::[Import_Schema] TO [Import_Role]
-- Engine_Role permissions on the engine schema
GRANT EXECUTE, DELETE, INSERT, SELECT, UPDATE, REFERENCES ON SCHEMA::[Engine_Schema] TO [Engine_Role]
EXEC sp_addrolemember N'Import_Role', N'Import_User'
EXEC sp_addrolemember N'Engine_Role', N'Engine_User'
GRANT CONNECT TO [Import_User]
GRANT CONNECT TO [Engine_User]
然后,我在每个模式中创建了一些表并存储了适用于每个角色的proc。引擎模式中可能有20个表,导入模式中大约有30个表。其中一些在两个模式中非常相似,但并不完全相同,例如:
CREATE TABLE [Engine_Schema].[Problem](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[Description] [varchar](max) NULL,
CONSTRAINT [PK_Status] PRIMARY KEY CLUSTERED ( [ID] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCK = ON) ON [PRIMARY])
ON [PRIMARY]
CREATE TABLE [Import_Schema].[Problem](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[Client] [varchar](50) NOT NULL,
[Description] [varchar](max) NULL,
CONSTRAINT [PK_Status] PRIMARY KEY CLUSTERED ( [ID] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCK = ON) ON [PRIMARY])
ON [PRIMARY]
当我通过SSMS检查使用这两次登录时,这一切似乎都很好——每次登录都能看到我期望的表和SP。在每种情况下,我都可以在SSMS中运行查询和USP,而无需使用模式前缀,因为这些连接使用我为每个登录/用户设置的默认模式。如果我以"sa"的身份登录,那么我当然可以看到这两个模式中的所有内容。
在我的C#代码中,我像这样连接到数据库:
SqlConnection dbConnection = new SqlConnection(""server=laptop; database=test; user id=Engine_User; password=*****; Trusted_Connection=yes; connection timeout=30");
dbConnection.Open();
然后我尝试像这样直接查询数据库表:
using (SqlCommand cmdSelectProblems = new SqlCommand()) {
cmdSelectProblems.Connection = dbConnection;
cmdSelectProblems.CommandText = "Select ID, Name from Problem order by Name";
DataTable dataTableProblems = new DataTable();
using (SqlDataAdapter dataAdapterProblems = new SqlDataAdapter(cmdSelectProblems)) {
dataAdapterProblems.Fill(dataTableProblems);
...
或者我可以尝试使用我的一个存储过程,如下所示:
using (SqlCommand cmd = new SqlCommand()) {
cmd.Connection = dbConnection;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "SelectProblems";
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
da.Fill(_problemsTable);
}
但是,当我像下面这些例子一样尝试通过C#代码使用连接时,我会遇到以下错误:
Invalid object name 'Problem'
或
Could not find stored procedure 'SelectProblems'
我似乎需要使用显式模式前缀来访问数据库中相同的DB对象。由于模式前缀明确包含了我测试过的C#代码中的所有内容,所以将直接表查询更改为:
cmdSelectProblems.CommandText = "Select ID, Name from [Engine_Schema].Problem order by Name";
或者尝试访问具有模式前缀的USP,如:
cmd.CommandText = "[Engine_Schema].SelectProblems";
然后一切都很好。
现在我知道使用显式模式名称是最佳实践,但我在C#和存储过程中都有一整套代码,这些代码是在不使用这些模式前缀的情况下编写的。如果我能让C#SqlConnection
查询尊重我定义和使用的登录名的默认模式,那就简单多了。我相信,按照我设置的方式,这应该很好,但我想我一定在某个地方错过了什么。
到目前为止,我已经在这方面浪费了两天时间,我所读到的一切都表明,这一切都应该奏效。
服务器=笔记本电脑;数据库=测试;user id=Engine_user;密码=*
Trusted_Connection=是;连接超时=30
这是您的问题-您使用的是Windows身份验证,而不是SQL身份验证。将连接字符串更改为Trusted_Connection=no
,一切正常。
在rmdbs 上设置用户默认模式
USE AdventureWorks;
ALTER USER Engine_User WITH DEFAULT_SCHEMA = Engine_Schema;
GO
对导入模式执行相同操作