2013-06-11 26 views
7

Không tạo DbContext cho mỗi truy vấn trong Asp.net làm cho EF chỉ đọc dữ liệu từ bộ nhớ cache của nó, hay nó truy vấn DB cho toàn bộ mỗi lần? Tôi biết về bộ nhớ đệm siêu dữ liệu cho mỗi AppDomain, nhưng những gì về chỉ là dữ liệu?EF có lưu trữ các thực thể giữa các trường hợp khác nhau của DbContext không?

Bối cảnh: thu thập dữ liệu và ứng dụng trực quan với giao diện MVC4 + Web API, sẽ không gọi là "khối lượng lớn", nhưng nhiều truy vấn trả lại cùng một tập hợp dữ liệu trong một khoảng thời gian ngắn hơn.

+0

tôi không nghĩ vậy dữ liệu được lưu trữ trong thực thể luôn là truy vấn DB –

Trả lời

13

Khuôn khổ thực thể không có bộ nhớ cache dữ liệu cho mỗi AppDomain, chỉ có bộ nhớ cache cho mỗi trường hợp ngữ cảnh.

Nếu bạn tạo ngữ cảnh mới theo yêu cầu hoặc truy vấn bạn bắt đầu bằng bộ đệm trống và EF sẽ tìm nạp dữ liệu từ cơ sở dữ liệu. Ngoài ra, thuật ngữ "cache cho mỗi bối cảnh ngữ cảnh" có thể gây hiểu nhầm vì nó không có nghĩa là EF sẽ không chạy các truy vấn tới cơ sở dữ liệu nếu các thực thể đã được nạp trong bộ nhớ cache ngữ cảnh. Cách làm thế nào các công trình này bộ nhớ cache và làm thế nào bạn có thể tận dụng nó (hay không) như sau:

  • Mỗi LINQ-to-Đối tượng truy vấn trên một DbSet<T> hoặc nói chung trên một IQueryable<T> sẽ chạy một truy vấn cơ sở dữ liệu, không có vấn đề gì nếu các thực thể đã tồn tại trong ngữ cảnh hay không. Nhưng nếu một thực thể có cùng khóa với thực thể được truy vấn đã tồn tại trong ngữ cảnh, EF sẽ ném kết quả của truy vấn đó đi và trả về cá thể thực thể được lưu trong bộ nhớ cache về người gọi.

    Thực hiện việc kiểm tra này nếu thực thể có cùng khóa tồn tại sau nó đã chạy truy vấn. (Đối với các truy vấn phức tạp - ví dụ truy vấn có chứa Include - không thể thực hiện việc kiểm tra này trước vì không thể nhận được đối tượng và giá trị khóa nào.)

    Đó là hành vi mặc định (MergeOptionAppendOnly). Bạn có thể thay đổi hành vi này thành OverwriteChanges và các tùy chọn khác, tôi tin, nhưng không ai trong số họ sẽ tránh được rằng truy vấn LINQ luôn đưa ra các truy vấn cơ sở dữ liệu.

  • Đối với truy vấn một thực thể chỉ bằng cách quan trọng của nó, bạn có thể sử dụng GetObjectByKey hoặc Find (với DbContext) mà sẽ kiểm tra đầu tiên nếu đơn vị có quan trọng mà đã được lưu trữ trong bối cảnh và sau đó trở về đối tượng lưu trữ này. Nếu không, nó sẽ chạy một truy vấn cơ sở dữ liệu để tải nó.

  • Bạn có thể truy vấn ChangeTracker của EF, nó được hỗ trợ đặc biệt tốt với DbContext nơi bạn có quyền truy cập vào bộ nhớ cache ngữ cảnh thông qua bộ sưu tập DbSet<T>.Local.

    Vấn đề ở đây là không có logic để truy vấn cơ sở dữ liệu tự động nếu truy vấn trên Local không trả lại kết quả. Bạn phải viết logic này bằng tay. Vấn đề lớn hơn nữa là truy vấn trên Local là LINQ-to-Objects chứ không phải LINQ-to-Entities (Local không triển khai IQueryable<T>, chỉ IEnumerable<T>), vì vậy bạn thường phải ghi lại truy vấn của mình để hành động trên Local - ví dụ bạn không thể sử dụng Include đây, bạn không thể sử dụng bất kỳ EntityFunctions, bạn sẽ nhận được hành vi khác nhau để so sánh chuỗi liên quan đến trường hợp nhạy cảm, vv, vv

+0

Cảm ơn lời giải thích tuyệt vời.Cho đến nay, tôi đã hoàn toàn bỏ lỡ thực tế là phiên bản được lưu trong bộ nhớ cache có thể được sử dụng, ngay cả khi các truy vấn được phát hành dựa vào cơ sở dữ liệu. Tôi đã sử dụng SQL Server Profiler và thấy các truy vấn không trả lại dữ liệu mới trong ứng dụng của tôi !? Cuối cùng tôi đã phát hiện ra rằng MembershipProvider tùy chỉnh của tôi đã được duy trì bởi khung công tác giữa yêu cầu và do đó, trường hợp ngữ cảnh được giữ lại. Mã khác đang chạy trong bối cảnh và mọi thứ đã hoàn toàn sai lầm. –

Các vấn đề liên quan