7

Visual Studio 2012 と Entity Framework 5 および SQL Server 2008 を使用してデータベース アプリケーションを作成しています。Entity Framework で SQL Server ユーザー (つまり、ログインしていないユーザー) を偽装したいと考えています。MyDatabaseEntities偽装するユーザーの名前の引数を含むDB コンテキストの新しいコンストラクターを作成しました。ここに私が書いたコードがあります:

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状態が変化していない場合でも、メソッド メソッドが実行されているように見えるためです。次に問題は、コードを2回実行すると、

public void RunSimpleQuery()
{
    using (MyDatabaseEntities context = new MyDatabaseEntities("UserName"))
    {
        var result = context.TableName.ToList();

    }

}

...Entity Framework は次をスローしSqlExceptionます。

現在のコマンドで重大なエラーが発生しました。結果がある場合は破棄する必要があります。\r\n現在のコマンドで重大なエラーが発生しました。結果がある場合は、破棄する必要があります。

何か案は?

更新 1

上記のコードで、変更しました...

cmd.CommandText = "EXECUTE AS USER = @user;";

...に...

cmd.CommandText = "REVERT; EXECUTE AS USER = @user;";

...そして、まだ同じSqlExceptionエラーが発生します。

4

2 に答える 2

6

The problem is that EF closes connection when it doesn't need it and returns it back to the pool. So when it executes some SQL again it request new connection from the pool where your event may not be initialized. But again I believe that you should try to solve this with manually controlling connection lifetime to have both benefit of connection pooling and be able to meet your requirements.

于 2013-02-08T09:31:30.373 に答える
2

私は古い質問であることを知っていますが、誰かにとって役立つかもしれません。

あなたのコードを使用して、別の方法で行いました...

それ以外の

Connection_StateChanged イベント

同じクラスに 2 つのメソッドを作成します。

    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 に答える