私はこれに出くわしました:
https://entityframework.codeplex.com/wikipage?title=傍受
そして、次のようなことができるようです:
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
of で行いました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; }
}
そして、このように私のdbコンテキストを拡張しました(もちろん、部分クラスを使用して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
私の差し迫った問題。