EFのSaveChangesメソッド/プロセスをオーバーライドする方法を探しています。なんらかの方法でSQLを取得し、通常の更新/削除/挿入が実行されないようにし、生成されたSQLを使用してカスタムプロシージャを実行する必要があります。
SaveChanges()
通常どおりお電話ください。EFにSQLを生成させます。- SQLを取得する
- そのSQLが通常の方法で実行されないようにする
- カスタムストアドプロシージャを呼び出します(追加のパラメータなどを取ります)
- 実行したふりをします
SaveChanges
(または単に0を返します)
私が目にする唯一の本当の問題は、SaveChanges
メソッド内からSQLを取得することです。私たちがすることは、理想的にはこのようなものです...
- プロバイダー/接続/などを取得
- これを処理するためのイベントフックを設定します
- 完了、コードの変更/オーバーライドなどはありません。
3文字の頭字語のデータベースに対してMVC4とEF5を使用しています。ここでのポイントは、各更新アクションでSQLを手動でコーディングすることを避け、EFに依存してすべてを生成することです。プロシージャはストレートSQLを使用するため
はい、これはそれを行うための良い方法ではありません(単一の手順)が、私たちは問題に選択の余地がありません。何もありません。これができない場合は、カスタムSQLを作成する必要があります。おそらく、これを強制することができる別の方法があります。そこでは、コンテキストを渡し、自分で作業を行いますか?次に、「SaveChanges()」が呼び出されないことを監査できます:D
解決
EFTracingProvider
私はこれ(および他のいくつかのこと)を行う独自のプロバイダーを作成するための開始点としてを使用しました。すべてをEntitiesクラスに配置し、イベントを処理することで、EFTracingProviderのみでそれを行うこともできます。このイベントはその後に発生するため、変更されたSQLは表示されないため、独自のロギングを行う必要があります。これは、Webサイトによりよく適合するように削除されました:)
public class MyEntities : MyBaseEntities
{
public MyEntities(): this(connectionString: "name=MyBaseEntities") {}
public MyEntities(string connectionString)
: base(MakeConnection(connectionString, "EFTracingProvider")) {}
/// <summary>
/// Insert the wrapped connection by calling the base toolkit.
private static EntityConnection MakeConnection(string connectionString, params string[] providers)
{
var conn = EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
connectionString,
providers
);
//get the tracing connection, so that we can attach event handlers
var us = conn.UnwrapConnection<EFTracingConnection>();
if (us != null)
{
us.CommandExecuting += BeforeExecute;
}
return conn;
}
private static void BeforeExecute(object sender, CommandExecutionEventArgs e)
{
// If an Create/Update/Delete action then we need to wrap it in our custom proc
if (IsCudAction(e.CommandTree))
{
var text = cmd.Parameters.Cast<DbParameter>().Aggregate(
cmd.CommandText,
(current, p) => current.Replace(p.ParameterName, SafeSql.Prepare(p.Value)));
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "[dbo].[ExecuteForMe]";
cmd.Parameters.Clear();
cmd.Parameters.AddRange(new[]
{
new SqlParameter("commandText", text),
new SqlParameter("extraInfo", "logging context")
});
}
}
public static bool IsCudAction(DbCommandTree commandTree)
{
if (commandTree is DbUpdateCommandTree) return true;
if (commandTree is DbDeleteCommandTree) return true;
if (commandTree is DbInsertCommandTree) return true;
if (commandTree is DbQueryCommandTree) return false;
if (commandTree is DbFunctionCommandTree) return false;
throw new InvalidOperationException("Unknown type of CommandTree: " + commandTree.GetType().Name);
}
}