Agregar una sugerencia de consulta al llamar a la función de valor de tabla

Estoy llamando a una función con valores de tabla desde el marco de la entidad y necesito poder agregar la option (recompile) porque el plan de ejecución que recoge no es óptimo. Al ejecutar la consulta en SQL Server Management Studio, se vería algo como esto:

 select * from dbo.fDE_myquery(0, 0, 3309, '7/1/2013', '7/1/2014', 0, 0) option (recompile) 

Por parte de EF, no hay forma de agregar esa sugerencia, AFAIK. La parte EF se ve algo así como:

 var query = from f in ctx.fDE_myQuery(aBool, anotherBool, StartDate, EndDate, someInt, moreBool) select f; 

Vi esta pregunta:

¿Cómo controlo el rastreo de parámetros y / o los consejos de consulta en el marco de la entidad?

Pero es antiguo, y la solución aceptada en realidad no proporciona suficiente información sobre cómo implementar realmente la solución sugerida (usar guías de planes) con el marco de entidades. Si esa es la única solución, ¿cómo se obtiene el marco de entidad para usar una guía de plan de todos modos?

Me encontré con esto:

https://entityframework.codeplex.com/wikipage?title=Interception

Y parece que puedes hacer algo como esto:

 public class HintInterceptor : DbCommandInterceptor { public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext interceptionContext) { command.CommandText += " option (recompile)"; base.ReaderExecuting(command, interceptionContext); } } 

Y registrarlo así (lo hice en Application_Start of global.asax.cs ):

 DbInterception.Add(new HintInterceptor()); 

Y te permitirá modificar el CommandText . El único problema es que ahora se adjunta para cada consulta de lector que podría ser un problema, ya que algunos de ellos podrían verse afectados negativamente por esa sugerencia. Supongo que puedo hacer algo con el contexto para descubrir si la pista es apropiada o no, o en el peor de los casos podría examinar el mismo CommandText .

No parece la solución más elegante o fina.

Editar : Desde el interceptorContext , puede obtener los DbContexts , así que DbContexts una interfaz que se ve así:

 public interface IQueryHintContext { string QueryHint { get; set; } bool ApplyHint { get; set; } } 

Y luego creé una clase que se deriva de mi DbContext original (generado por EF) e implementa la interfaz anterior. Luego cambié mi interceptor para que se vea así:

 public class HintInterceptor : DbCommandInterceptor { public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext 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); } } 

Ahora, para usarlo, creo un contexto usando mi clase derivada en lugar del original, establezco QueryHint en lo que yo quiero que sea ( recompile en este caso) y establezco ApplyHint justo antes de ejecutar el comando y luego lo configuro en falso.

Para hacer esto un poco más autónomo, terminé definiendo una interfaz como esta:

 public interface IQueryHintContext { string QueryHint { get; set; } bool ApplyHint { get; set; } } 

Y extendí mi contexto db de esta manera (por supuesto, podrías usar una clase parcial para extender la clase EF también generada):

 public class MyEntities_Ext : MyEntities, IQueryHintContext { public string QueryHint { get; set; } public bool ApplyHint { get; set; } } 

Y luego, para hacer que la parte de encendido y apagado sea un poco más fácil de manejar, definí esto:

 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; } } 

Ahora para usarlo, puedo hacer solo esto:

 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 } 

Esto puede ser un poco exagerado y podría desarrollarse más (por ejemplo, usar una enumeración de sugerencias disponibles en lugar de una cadena, o crear una sugerencia de consulta de recompile para que no tenga que especificar la recompile cadena cada vez y arriesgarse a un error tipográfico), pero resolvió mi problema inmediato.