Saya menemukan ini:
https://entityframework.codeplex.com/wikipage?title=Interception
Dan tampaknya Anda dapat melakukan sesuatu seperti ini:
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);
}
}
Dan daftarkan seperti ini (saya melakukannya di Application_Start
dari global.asax.cs
):
DbInterception.Add(new HintInterceptor());
Dan itu akan membiarkan Anda mengubah CommandText
. Satu-satunya masalah adalah sekarang dilampirkan untuk setiap permintaan pembaca yang mungkin menjadi masalah karena beberapa dari mereka mungkin terkena dampak negatif oleh petunjuk itu. Saya kira saya bisa melakukan sesuatu dengan konteksnya untuk mencari tahu apakah petunjuknya sesuai atau tidak, atau lebih buruk lagi saya bisa memeriksa CommandText
sendiri.
Tampaknya bukan solusi yang paling elegan atau halus.
Sunting :Dari interceptorContext
, Anda bisa mendapatkan DbContexts
, jadi saya mendefinisikan antarmuka yang terlihat seperti ini:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
Dan kemudian membuat kelas yang berasal dari DbContext asli saya (dihasilkan oleh EF) dan mengimplementasikan antarmuka di atas. Kemudian saya mengubah pencegat saya menjadi seperti ini:
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);
}
}
Sekarang untuk menggunakannya, saya membuat konteks menggunakan kelas turunan saya alih-alih yang asli, atur QueryHint
untuk apa pun yang saya inginkan (recompile
dalam hal ini) dan atur ApplyHint
tepat sebelum saya menjalankan perintah dan mengembalikannya ke false setelahnya.
Untuk membuat semua ini sedikit lebih mandiri, saya akhirnya mendefinisikan antarmuka seperti ini:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
Dan memperluas konteks db saya seperti ini (Anda tentu saja dapat menggunakan kelas parsial untuk memperluas kelas yang dihasilkan EF juga):
public class MyEntities_Ext : MyEntities, IQueryHintContext
{
public string QueryHint { get; set; }
public bool ApplyHint { get; set; }
}
Dan kemudian, untuk membuat bagian pengaktifan dan penonaktifan sedikit lebih mudah ditangani, saya mendefinisikan ini:
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;
}
}
Sekarang untuk menggunakannya, saya bisa melakukan ini:
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
}
Ini mungkin sedikit berlebihan dan dapat dikembangkan lebih lanjut (misalnya, menggunakan enum untuk petunjuk yang tersedia alih-alih string - atau mensubklasifikasikan recompile
petunjuk kueri sehingga Anda tidak perlu menentukan string recompile
setiap kali dan berisiko salah ketik), tetapi itu memecahkan masalah langsung saya.