Tôi đã xem qua này:
https://entityframework.codeplex.com/wikipage?title=Interception
Và có vẻ như bạn có thể làm một cái gì đó như thế này:
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);
}
}
Và đăng ký nó như thế này (tôi đã làm nó trong Application_Start
của global.asax.cs
) :
DbInterception.Add(new HintInterceptor());
Và nó sẽ wil l cho phép bạn thay đổi CommandText
. Vấn đề duy nhất là nó hiện được đính kèm cho mỗi truy vấn đọc có thể là vấn đề vì một số trong số đó có thể bị tác động tiêu cực bởi gợi ý đó. Tôi đoán tôi có thể làm một cái gì đó với bối cảnh để tìm ra nếu gợi ý là thích hợp hay không, hoặc tệ hơn trường hợp tôi có thể kiểm tra các CommandText
chính nó.
Không hoàn toàn có vẻ là giải pháp trang nhã hoặc tinh tế nhất.
Sửa: Từ interceptorContext
, bạn có thể lấy DbContexts
, vì vậy tôi định nghĩa một giao diện trông như thế này:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
Và sau đó tạo ra một lớp dẫn xuất từ DbContext ban đầu của tôi (được tạo ra bởi EF) và triển khai giao diện trên. Sau đó, tôi đã thay đổi đánh chặn của tôi trông như thế này:
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);
}
}
Bây giờ sử dụng nó, tôi tạo ra một bối cảnh sử dụng lớp được thừa kế của tôi thay vì bản gốc, thiết QueryHint
để bất cứ điều gì tôi muốn nó được (recompile
trong trường hợp này) và đặt ApplyHint
ngay trước khi tôi thực thi lệnh và đặt lại thành false sau đó.
Để làm hơn tất cả điều này một chút khép kín, tôi đã kết thúc việc xác định một giao diện như thế này:
public interface IQueryHintContext
{
string QueryHint { get; set; }
bool ApplyHint { get; set; }
}
Và mở rộng bối cảnh db của tôi như thế này (bạn có thể, tất nhiên, chỉ cần sử dụng một lớp học phần để mở rộng các lớp EF tạo cũng):
public class MyEntities_Ext : MyEntities, IQueryHintContext
{
public string QueryHint { get; set; }
public bool ApplyHint { get; set; }
}
Và sau đó, để làm cho turn-on, turn-off phần một chút dễ dàng hơn để xử lý, tôi định nghĩa này:
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;
}
}
Bây giờ sử dụng nó, tôi có thể làm chỉ này:
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
}
này có lẽ hơi quá mức cần thiết và có thể phát triển hơn nữa (ví dụ, sử dụng một enum cho gợi ý có sẵn thay vì một chuỗi - hoặc subclassing một truy vấn recompile
gợi ý, do đó bạn không cần phải chỉ định chuỗi recompile
mỗi lần và có nguy cơ lỗi đánh máy), nhưng nó đã giải quyết được vấn đề trước mắt của tôi.
Bạn có thể giải thích thêm về cách bạn gọi nó không? –
Thêm 'tùy chọn (biên dịch lại)' mất> 10 giây truy vấn LINQ mà tôi đã xử lý trong vài ngày tới <1 giây. Ý tưởng tuyệt vời bằng cách sử dụng một kẻ đánh chặn để thêm nó. –
@drexdrex: Tôi mở rộng thêm một chút. Hy vọng nó giúp. –