Попаднах на това:
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; }
}
И разширих моя 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
}
Това може би е леко излишно и може да бъде доразвито (например, като се използва enum за налични съвети вместо низ - или подкласове recompile
намек за заявка, така че не е необходимо да посочвате низа recompile
всеки път и рискувам печатна грешка), но това реши непосредствения ми проблем.