me deparei com isso:
https://entityframework.codeplex.com/wikipage?title=Interception
E parece que você pode fazer algo assim:
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);
}
}
E registre assim (eu fiz isso em
Application_Start
de global.asax.cs
):DbInterception.Add(new HintInterceptor());
E permitirá que você altere o
CommandText
. O único problema é que agora está anexado para todos consulta do leitor, o que pode ser um problema, pois alguns deles podem ser afetados negativamente por essa dica. Acho que posso fazer algo com o contexto para descobrir se a dica é apropriada ou não, ou pior caso, poderia examinar o CommandText
em si. Não parece a solução mais elegante ou refinada.
Editar :Do
interceptorContext
, você pode obter os DbContexts
, então eu defini uma interface que se parece com isso:public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
E então criei uma classe que deriva do meu DbContext original (gerado pelo EF) e implementa a interface acima. Então eu mudei meu interceptor para ficar assim:
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);
}
}
Agora, para usá-lo, crio um contexto usando minha classe derivada em vez da original, defina
QueryHint
para o que eu quiser (recompile
neste caso) e defina ApplyHint
logo antes de executar o comando e configurá-lo de volta para false depois. Para tornar tudo isso um pouco mais autocontido, acabei definindo uma interface assim:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
E estendi meu contexto de banco de dados assim (você também pode usar uma classe parcial para estender a classe gerada pelo EF):
public class MyEntities_Ext : MyEntities, IQueryHintContext
{
public string QueryHint { get; set; }
public bool ApplyHint { get; set; }
}
E então, para tornar a parte de ligar e desligar um pouco mais fácil de manusear, defini isso:
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;
}
}
Agora, para usá-lo, posso fazer apenas isso:
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
}
Isso pode ser um pouco exagerado e pode ser desenvolvido ainda mais (por exemplo, usando um enum para dicas disponíveis em vez de uma string - ou subclassificando um
recompile
dica de consulta para que você não precise especificar a string recompile
toda vez e arriscar um erro de digitação), mas resolveu meu problema imediato.