私はこれに出くわしました:
https://entityframework.codeplex.com/wikipage?title=Interception
そして、あなたはこのようなことをすることができるようです:
public class HintInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
command.CommandText += " option (recompile)";
base.ReaderExecuting(command, interceptionContext);
}
}
そして、このように登録します(Application_Start
で登録しました global.asax.cs
の ):
DbInterception.Add(new HintInterceptor());
また、CommandText
を変更できます 。唯一の問題は、すべてに接続されていることです。 それらのいくつかはそのヒントによって悪影響を受ける可能性があるため、問題になる可能性のあるリーダークエリ。ヒントが適切かどうかを判断するためにコンテキストを使って何かを行うことができると思います。最悪の場合、CommandText
を調べることができます。
最もエレガントできめの細かいソリューションではないようです。
編集 :interceptorContext
から 、DbContexts
を取得できます 、それで私は次のようなインターフェースを定義しました:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
次に、元のDbContext(EFによって生成された)から派生し、上記のインターフェイスを実装するクラスを作成しました。次に、インターセプターを次のように変更しました:
public class HintInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
if (interceptionContext.DbContexts.Any(db => db is Dal.IQueryHintContext))
{
var ctx = interceptionContext.DbContexts.First(db => db is Dal.IQueryHintContext) as Dal.IQueryHintContext;
if (ctx.ApplyHint)
{
command.CommandText += string.Format(" option ({0})", ctx.QueryHint);
}
}
base.ReaderExecuting(command, interceptionContext);
}
}
これを使用するために、元のクラスの代わりに派生クラスを使用してコンテキストを作成し、QueryHint
を設定します。 私が望むものに(recompile
この場合)、ApplyHint
を設定します コマンドを実行する直前に、コマンドをfalseに戻します。
これをもう少し自己完結型にするために、私は次のようなインターフェースを定義することになりました:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
そして、このようにデータベースコンテキストを拡張しました(もちろん、部分クラスを使用してEFで生成されたクラスを拡張することもできます):
public class MyEntities_Ext : MyEntities, IQueryHintContext
{
public string QueryHint { get; set; }
public bool ApplyHint { get; set; }
}
次に、ターンオンとターンオフの部分を少し扱いやすくするために、次のように定義しました。
public class HintScope : IDisposable
{
public IQueryHintContext Context { get; private set; }
public void Dispose()
{
Context.ApplyHint = false;
}
public HintScope(IQueryHintContext context, string hint)
{
Context = context;
Context.ApplyHint = true;
Context.QueryHint = hint;
}
}
今それを使用するために、私はこれを行うことができます:
using (var ctx = new MyEntities_Ext())
{
// any code that didn't need the query hint
// ....
// Now we want the query hint
using (var qh = new HintScope(ctx, "recompile"))
{
// query that needs the recompile hint
}
// back to non-hint code
}
これは少しやり過ぎかもしれませんし、さらに発展させることができます(たとえば、文字列の代わりに利用可能なヒントの列挙型を使用するか、recompile
をサブクラス化する 文字列recompile
を指定する必要がないようにヒントを照会します 毎回、タイプミスのリスクがあります)が、それは私の当面の問題を解決しました。