我遇到过这个:
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
。唯一的问题是它现在已附加到every读者查询这可能是一个问题,因为其中一些可能会受到该提示的负面影响。我猜我可以根据上下文做一些事情来确定提示是否合适,或者更糟糕的情况我可以检查CommandText
itself.
看起来并不是最优雅或最细粒度的解决方案。
Edit: 来自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
每次都冒着打字错误的风险),但它解决了我眼前的问题。