7

我正在使用带有 Entity Framework 5 和 SQL Server 2008 的 Visual Studio 2012 编写数据库应用程序。我希望 Entity Framework 模拟 SQL Server 用户(即没有登录的用户)。我为数据库上下文创建了一个新的构造函数,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_StateChange即使状态没有改变,方法 method 似乎也会执行。那么问题是当我运行代码两次时,

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错误。

4

2 回答 2

6

问题是 EF 在不需要时关闭连接并将其返回到池中。因此,当它再次执行一些 SQL 时,它会从您的事件可能未初始化的池中请求新连接。但是我再次相信您应该尝试通过手动控制连接生命周期来解决这个问题,以便既受益于连接池又能够满足您的要求。

于 2013-02-08T09:31:30.373 回答
2

我知道这是一个老问题,但也许对某人有用。

我以不同的方式使用您的代码...

代替

Connection_StateChanged 事件

我在同一个类中创建了两个方法:

    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;
        }

它适用于 SP,即使在多次执行后也不会引发异常。如果我可以在命令执行后捕获一个事件,那么可能都被封装在 MyDatabaseEntities 上。

于 2014-10-21T19:41:06.120 回答