Visual studio 2012 实体框架5-实现SQL Server“;“以用户身份执行”;
我正在使用Visual Studio 2012、Entity Framework 5和SQL Server 2008编写一个数据库应用程序。我希望实体框架模拟SQL Server用户(即未登录的用户)。我已经为DB contextVisual studio 2012 实体框架5-实现SQL Server“;“以用户身份执行”;,visual-studio-2012,sql-server-2008-r2,entity-framework-5,impersonation,Visual Studio 2012,Sql Server 2008 R2,Entity Framework 5,Impersonation,我正在使用Visual Studio 2012、Entity Framework 5和SQL Server 2008编写一个数据库应用程序。我希望实体框架模拟SQL Server用户(即未登录的用户)。我已经为DB contextMyDatabaseEntities创建了一个新的构造函数,其中包含一个用于模拟用户名称的参数。以下是我编写的代码: public partial class MyDatabaseEntities { private String _impersonateUse
MyDatabaseEntities
创建了一个新的构造函数,其中包含一个用于模拟用户名称的参数。以下是我编写的代码:
public partial class MyDatabaseEntities
{
private String _impersonateUser = null;
public MyDatabaseEntities(String impersonateUser)
: base("MyConnectionString")
{
_impersonateUser = impersonateUser;
this.Database.Connection.StateChange += Connection_StateChange;
}
void Connection_StateChange(object sender, StateChangeEventArgs e)
{
if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open)
{
using (var cmd = this.Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("user", _impersonateUser));
cmd.CommandText = "EXECUTE AS USER = @user";
cmd.ExecuteNonQuery();
}
}
}
我必须加上支票
if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open)
…因为方法Connection\u StateChange
方法似乎在状态未更改时也会执行。然后问题是,当我运行代码两次时
public void RunSimpleQuery()
{
using (MyDatabaseEntities context = new MyDatabaseEntities("UserName"))
{
var result = context.TableName.ToList();
}
}
…实体框架抛出一个SqlException
:
当前命令发生严重错误。结果如何
任何,都应丢弃。\r\n当前服务器上发生严重错误
指挥部。如果有结果,则应放弃
有什么想法吗
更新1
我在我的代码上面,我改变了
cmd.CommandText = "EXECUTE AS USER = @user;";
…到
cmd.CommandText = "REVERT; EXECUTE AS USER = @user;";
…我仍然得到相同的
SqlException
错误。问题是EF在不需要连接时关闭连接并将其返回到池中。因此,当它再次执行某些SQL时,它会从可能未初始化事件的池中请求新连接。但我再次相信,您应该尝试通过手动控制连接生存期来解决这个问题,这样既可以获得连接池的好处,又可以满足您的要求。我知道这是一个老问题,但可能对某些人有用
我用另一种方式,用你的代码
而不是
连接状态已更改事件
我在同一个类中创建了两个方法:
public void ChangeUser(String sUser)
{
if(Database.Connection.State != ConnectionState.Open)
Database.Connection.Open();
using (var cmd = Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("user", sUser));
cmd.CommandText = "EXECUTE AS USER = @user;";
cmd.ExecuteNonQuery();
}
}
public void Revert()
{
if (Database.Connection.State != ConnectionState.Open)
Database.Connection.Open();
using (var cmd = Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "REVERT;";
cmd.ExecuteNonQuery();
}
}
我在执行存储过程之前和之后使用它
using (var db = new MyDatabaseEntities())
{
db.ChangeUser(model.Username);
var result = db.Something();
db.Revert();
return result;
}
它可以与SPs配合使用,即使在多次执行之后也不会抛出异常。如果我能在命令执行后捕捉到一个事件,可能所有事件都会被封装在MyDatabaseEntities上。问题是EF在不需要时关闭连接,并将其返回到池中。因此,当它再次执行某些SQL时,它会从可能未初始化事件的池中请求新连接。@LadislavMrnka是的,您确定了问题所在。我想我必须在连接字符串中指定不使用连接池…这太可惜了。请为此创建一个答案(只需说出你在评论中所说的),这样我就可以给你评分了。谢谢您应该尝试自己控制连接(通过将其传递给DbContext),但这有一些问题:@LadislavMrnka我将重载MyDatabaseEntities构造函数,并为其提供所需的连接字符串(无需为模拟进行池化)。我将在更新中发布我的代码。同样,请提供答案(复制并粘贴您的评论),这样我就可以给您评分了!=)好问题。你有没有做到这一点,如果有,你能发布一个答案,说明你做了什么吗?再次感谢你的帮助!顺便说一句:我接受你关于手动控制连接生存时间的建议,以获得模拟连接池的好处(你提供的链接非常有用)。我想我会按照你的方式去做。我将更新我的代码并将其作为另一个更新发布。