Ik kwam dit tegen:
https://entityframework.codeplex.com/wikipage?title=Interceptie
En het lijkt erop dat je zoiets als dit kunt doen:
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);
}
}
En registreer het als volgt (ik deed het in Application_Start
van global.asax.cs
):
DbInterception.Add(new HintInterceptor());
En je kunt de CommandText
. wijzigen . Het enige probleem is dat het nu is bijgevoegd voor elke lezerquery, wat een probleem kan zijn, omdat sommige van hen negatief kunnen worden beïnvloed door die hint. Ik vermoed dat ik iets met de context kan doen om erachter te komen of de hint gepast is of niet, of in het ergste geval zou ik de CommandText
kunnen onderzoeken zelf.
Lijkt niet echt de meest elegante of fijnmazige oplossing.
Bewerken :Van de interceptorContext
, kunt u de DbContexts
, dus ik heb een interface gedefinieerd die er als volgt uitziet:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
En vervolgens een klasse gemaakt die is afgeleid van mijn originele DbContext (gegenereerd door EF) en de bovenstaande interface implementeert. Toen veranderde ik mijn interceptor om er zo uit te zien:
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);
}
}
Om het nu te gebruiken, maak ik een context met behulp van mijn afgeleide klasse in plaats van de originele, set QueryHint
naar wat ik maar wil (recompile
in dit geval) en stel ApplyHint
in vlak voordat ik het commando uitvoer en het daarna weer op false zet.
Om dit allemaal een beetje meer op zichzelf staand te maken, heb ik uiteindelijk een interface als volgt gedefinieerd:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
En breidde mijn db-context op deze manier uit (je zou natuurlijk ook een gedeeltelijke klasse kunnen gebruiken om de door EF gegenereerde klasse uit te breiden):
public class MyEntities_Ext : MyEntities, IQueryHintContext
{
public string QueryHint { get; set; }
public bool ApplyHint { get; set; }
}
En om het in- en uitschakelen een beetje gemakkelijker te maken, heb ik dit gedefinieerd:
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;
}
}
Om het nu te gebruiken, kan ik precies dit doen:
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
}
Dit is misschien een beetje overdreven en zou verder kunnen worden ontwikkeld (bijvoorbeeld een opsomming gebruiken voor beschikbare hints in plaats van een tekenreeks - of een recompile
subclasseren vraaghint zodat u de tekenreeks recompile
niet hoeft op te geven elke keer en riskeer een typfout), maar het loste mijn onmiddellijke probleem op.