Entity Frameworkを使用してすべてのデータ変更を記録する

entity-framework logging

質問

顧客からは、すべてのデータ変更を、変更を加えた実際のユーザーとともにログ記録テーブルに記録する必要があります。アプリケーションはデータベースへのアクセスに1人のSQLユーザーを使用していますが、 "実際の"ユーザーIDをログに記録する必要があります。

t-sqlでは、テーブルの挿入と更新ごとにトリガーを作成し、context_infoを使用してユーザーIDを格納することでこれを実現できます。ユーザーIDをストアドプロシージャに渡し、そのユーザーIDをcontextinfoに格納し、トリガはこの情報を使用してログ行をログテーブルに書き込むことができます。

EFを使って似たようなことができる場所や方法が見つからない。そのため、主な目標は、EFを介してデータを変更した場合、正確なデータ変更を半自動でテーブルに記録することです(したがって、変更前にすべてのフィールドをチェックしたくはありません)。オブジェクトを保存します。 EntitySQLを使用しています。

残念ながら、SQL 2000に固執する必要があるため、SQL 2008で導入されたデータ変更キャプチャは選択肢にはなりません(ただし、これは正しい方法ではないかもしれません)。

アイデア、リンク、または出発点はありますか。

[編集]いくつかのメモ:ObjectContext.SavingChangesイベントハンドラを使うことで、contextinfoを初期化するためにSQL文を注入することができるポイントを得ることができます。しかし、EFと標準SQLを混在させることはできません。そのため、EntityConnectionを取得できますが、それを使用してT-SQLステートメントを実行することはできません。あるいは、EntityConnectionの接続文字列を取得し、それに基づいてSqlConnectionを作成することもできますが、それは別の接続になるため、contextinfoはEFによる保存には影響しません。

SavingChangesハンドラで次のことを試しました。

testEntities te = (testEntities)sender;
DbConnection dc = te.Connection;
DbCommand dcc = dc.CreateCommand();
dcc.CommandType = CommandType.StoredProcedure;
DbParameter dp = new EntityParameter();
dp.ParameterName = "userid";
dp.Value = textBox1.Text;
dcc.CommandText = "userinit";
dcc.Parameters.Add(dp);
dcc.ExecuteNonQuery();

エラー:EntityCommand.CommandTextの値はStoredProcedureコマンドには無効です。 EntityParameterではなくSqlParameterと同じです。SqlParameterは使用できません。

StringBuilder cStr = new StringBuilder("declare @tx char(50); set @tx='");
cStr.Append(textBox1.Text);
cStr.Append("'; declare @m binary(128); set @m = cast(@tx as binary(128)); set context_info @m;");

testEntities te = (testEntities)sender;
DbConnection dc = te.Connection;
DbCommand dcc = dc.CreateCommand();
dcc.CommandType = CommandType.Text;
dcc.CommandText = cStr.ToString();
dcc.ExecuteNonQuery();

エラー:クエリ構文は無効です。

だからここで私は、Entity FrameworkとADO.NETの間の橋渡しをするために立ち往生しています。うまく動くようになれば、概念実証を投稿します。

受け入れられた回答

Contextの扱いはどうですか。 節約の変化


人気のある回答

私を正しい方向に向けてくれてありがとう。ただし、私の場合は、select文を実行するときにコンテキスト情報も設定する必要があります。これは、コンテキスト情報を使用してユーザーによる行レベルのセキュリティを制御するビューをクエリしているためです。

私は、接続のStateChangedイベントにアタッチして、非オープンからオープンへの変更を監視するのが最も簡単であることに気付きました。その後、コンテキストを設定するprocを呼び出します。EFが接続をリセットすることを決定したとしても、それは毎回動作します。

private int _contextUserId;

public void SomeMethod()
{
    var db = new MyEntities();
    db.Connection.StateChange += this.Connection_StateChange;
    this._contextUserId = theCurrentUserId;

    // whatever else you want to do
}

private void Connection_StateChange(object sender, StateChangeEventArgs e)
{
    // only do this when we first open the connection
    if (e.OriginalState == ConnectionState.Open ||
        e.CurrentState != ConnectionState.Open)
        return;

    // use the existing open connection to set the context info
    var connection = ((EntityConnection) sender).StoreConnection;
    var command = connection.CreateCommand();
    command.CommandText = "proc_ContextInfoSet";
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("ContextUserID", this._contextUserId));
    command.ExecuteNonQuery();
}


Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ