2013-04-05 14 views
39

Tôi mới vào Khung thực thể.Entity Framework Caching Issue

Tôi đã nhận được một số giá trị trong cơ sở dữ liệu của mình bằng EF. Nó trả về hoàn hảo và các giá trị được hiển thị trong nhãn. Nhưng khi tôi xóa tất cả các giá trị trong bảng của tôi (không sử dụng EF), truy vấn EF sẽ trả lại các giá trị cũ của tôi. Tôi biết EF lưu trữ các giá trị trong bộ nhớ cache và trả về dữ liệu được lưu trong bộ nhớ cache cho các lần chạy tiếp theo. Điều này có đúng không?

Vậy làm thế nào tôi có thể giải quyết vấn đề khi tôi đã xóa tất cả các giá trị trong cơ sở dữ liệu của mình, nhưng EF trả về giá trị cũ?

Sửa:

Bây giờ tôi sử dụng datamodel.SaveChanges(). Nhưng bây giờ nó trở về cùng một giá trị cũ.

truy vấn mẫu của tôi là trông giống như dưới đây:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities(); 
datamodel.SaveChanges(); 
List<Compliance> compliance=new List<Compliance>(); 
IList<ComplianceModel> complianceModel; 
if (HttpContext.Current.User.IsInRole("SuperAdmin")) 
{ 
    compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList(); 
} 
+3

Bạn có gọi '.SaveChanges();' trên dbContext của bạn không? Nếu bạn không phải là các thực thể sẽ không bị xóa .. – Rob

+0

Vui lòng đọc câu hỏi đầy đủ của tôi. Tôi did't sử dụng xóa trong code.I xóa các giá trị trong cơ sở dữ liệu thẳng –

+0

Làm thế nào về bối cảnh của bạn? Mở ngữ cảnh khi bạn cần và đóng nó ngay khi bạn hoàn thành. (Bạn có thể muốn cải thiện câu hỏi của mình, hoàn toàn không rõ ràng) –

Trả lời

25

Nếu bạn biết rằng những thay đổi xảy ra bên ngoài của EF và muốn làm mới ctxt của bạn cho một tổ chức cụ thể, bạn có thể gọi ObjectContext.Refresh

datamodel.Refresh(RefreshMode.StoreWins, orders); 

Nếu đây có vẻ như nó sẽ là một sự xuất hiện phổ biến, bạn nên vô hiệu hóa đối tượng bộ nhớ đệm trong các truy vấn của bạn:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities(); 
datamodel.tblCities.MergeOption = MergeOption.NoTracking; 

hoặc tắt đối tượng mức bộ nhớ đệm cho Entity cụ thể,

Context.Set<Compliances>().AsNoTracking(); 
+3

.AsNoTracking() cho tôi – nadav

+1

Nếu AsNoTracking() được sử dụng, sau đó DBContext sẽ không theo dõi các thay đổi đối với các Enetities. Trong trường hợp đó, bạn sẽ không thể sửa đổi các thực thể và lưu chúng bằng cách sử dụng dbContext.SaveChanges(). –

+1

http://codethug.com/2016/02/19/Entity-Framework-Cache-Busting/ –

20

EF sẽ không tải thay đổi trừ khi bạn truy vấn ngữ cảnh. EF truy vấn db và tải bản đồ chúng vào các đối tượng, nó theo dõi những thay đổi bạn thực hiện trên các đối tượng chứ không phải trên cơ sở dữ liệu. EF không theo dõi các thay đổi được thực hiện trực tiếp cho cơ sở dữ liệu và nó sẽ không bao giờ theo dõi.

Bạn đã tải Danh sách, Danh sách đó là bộ nhớ cache của bạn trong bộ nhớ. Ngay cả khi gọi Save Changes sẽ không làm mới. Bạn sẽ phải truy vấn lại bối cảnh một lần nữa, đó là tạo danh sách mới.

Để xem những thay đổi Bạn sẽ phải thực hiện sau dòng một lần nữa,

datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList() 
25

Khi bạn sử dụng EF nó bằng cách tải mặc định mỗi thực thể duy nhất một lần mỗi ngữ cảnh. Truy vấn đầu tiên tạo ra instace thực thể và lưu trữ nó trong nội bộ. Bất kỳ truy vấn tiếp theo nào yêu cầu pháp nhân có cùng khóa trả về phiên bản được lưu trữ này. Nếu giá trị trong lưu trữ dữ liệu thay đổi bạn vẫn nhận được đơn vị với giá trị từ các truy vấn ban đầu

Một câu trả lời cẩn thận:

https://stackoverflow.com/a/3653392/1863179

+8

Phiên bản ngắn: "Không bao giờ sử dụng ngữ cảnh toàn cầu" – Colin

+1

Tôi đã gỡ lỗi như điên, đi sâu vào SSMS và kiểm tra mọi thứ tôi có thể tìm tại sao một số cuộc gọi không được cập nhật ... Bây giờ tôi biết! Cảm ơn bạn! – RemarkLima

4

Dưới đây đang giúp đối tượng của tôi được làm mới với các giá trị cơ sở dữ liệu tươi . Lệnh nhập cảnh (đối tượng) .Reload() lực lượng đối tượng để thu hồi cơ sở dữ liệu giá trị

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName); 
DatabaseObjectContext.Entry(member).Reload(); 
4

tôi khuyên bạn nên sử dụng một số MergeOption cho tất cả EntitieSet sau khi tạo ra bối cảnh, như thế này:

var objSetProps = ctx.GetType().GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ObjectSet<>)); 
foreach (PropertyInfo objSetProp in objSetProps) 
{ 
    ObjectQuery objSet = (ObjectQuery)objSetProp.GetValue(ctx, BindingFlags.GetProperty, null, null, null); 
    objSet.MergeOption = MergeOption.PreserveChanges; 
} 

đọc về MergeOption tại đây: http://msdn.microsoft.com/en-us/library/system.data.objects.mergeoption.aspx Bạn sẽ sử dụng NoTracking, tôi nghĩ vậy.

Nhưng, bạn có thể xóa các thực thể "được lưu trong bộ nhớ cache", tách nó ra.

var entidades = Ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged); 
foreach (var objectStateEntry in entidades) 
    Ctx.Detach(objectStateEntry.Entity); 

Trường hợp Ctx là ngữ cảnh của tôi.

2

Trước hết tôi sẽ không đề nghị sửa đổi cơ sở dữ liệu bên ngoài hệ thống của bạn trừ khi bạn chỉ đang thử nghiệm và phát triển.

EF DbContext chứa giao diện IDisposable. Để giải phóng bất kỳ dữ liệu được lưu trong bộ nhớ cache nào, hãy thực hiện các cuộc gọi Dispose theo cách thủ công hoặc đặt Đối tượng Cơ sở dữ liệu của bạn bên trong khối sử dụng.

 using (SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities()) 
     { 
      List<Compliance> compliance = new List<Compliance>(); 
      IList<ComplianceModel> complianceModel; 
      if (HttpContext.Current.User.IsInRole("SuperAdmin")) 
      { 
       compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList(); 
      } 
     } 

Điều này sẽ đảm bảo bối cảnh được xóa và tạo lại lần sau khi sử dụng. Đảm bảo thực hiện việc này cho tất cả các cuộc gọi của bạn chứ không phải chỉ là cuộc gọi mà bạn đang gặp sự cố.

2

Tôi nghi ngờ rằng vấn đề cơ bản ở đây là DbContext của bạn bị treo quá lâu. Tôi có thể nói từ thực tế là bạn đang sử dụng HttpContext rằng bạn có một ứng dụng web, và General guidelines when working with DbContext bao gồm

Khi làm việc với các ứng dụng Web, sử dụng một trường hợp bối cảnh mỗi yêu cầu.

Nếu bạn đang sử dụng MVC bạn có thể sử dụng mô hình Vứt bỏ trong điều khiển của bạn như thế này:

public class EmployeeController : Controller 
{ 
    private EmployeeContext _context; 

    public EmployeeController() 
    { 
     _context = new EmployeeContext(); 
    } 

    public ActionResult Index() 
    { 
     return View(_context.Employees.ToList()); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      _context.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 
} 

Nhưng bạn thực sự nên được nhìn dependency injection để manage the DbContext lifetime

0

điều Couple bạn có thể làm.

  1. Sử dụng ngữ cảnh mới. Các thực thể được lưu trữ được lưu trữ trong ngữ cảnh. Sử dụng ngữ cảnh mới ngăn không cho nó sử dụng bộ nhớ cache.
  2. Nếu bạn thực sự muốn có bối cảnh toàn cầu/lâu dài, bạn có hai tùy chọn phụ: a.) Luôn gọi phương thức Nạp lại. db.Entry (entity) .Reload() ... này buộc bối cảnh tải lại thực thể đó. b.) Sử dụng đối tượng SqlDependency để phát hiện khi nào các bản ghi thay đổi và tải lại các thực thể khi cần. https://code.msdn.microsoft.com/How-to-use-SqlDependency-5c0da0b3
2

Tôi nghĩ điều bạn cần là GetDatabaseValues(). Nó được sử dụng như:

context.Entry(/*your entry*/).GetDatabaseValues(); 

Thông tin dưới đây là từ msdn:

Các giá trị hiện tại là những giá trị mà các thuộc tính của thực thể hiện chứa. Giá trị ban đầu là các giá trị được đọc từ cơ sở dữ liệu khi thực thể được truy vấn. Các giá trị cơ sở dữ liệu là các giá trị như chúng hiện đang được lưu trữ trong cơ sở dữ liệu.Nhận các giá trị cơ sở dữ liệu hữu ích khi các giá trị trong cơ sở dữ liệu có thể đã thay đổi kể từ khi thực thể được truy vấn như khi chỉnh sửa đồng thời với cơ sở dữ liệu đã được thực hiện bởi một người dùng khác.

7

Tôi nghĩ bạn nên làm theo một số giải pháp khác ở đây, nhưng có vẻ như bạn muốn xóa bộ nhớ cache. Bạn có thể đạt được điều này bằng cách thực hiện như sau:

var count = datamodel.Compliances.Local.Count; // number of items in cache (ex. 30) 

datamodel.Compliances.Local.ToList().ForEach(c => { 
    datamodel.Entry(c).State = EntityState.Detached; 
}); 

count = datamodel.Compliances.Local.Count; // 0 
+0

Đây là giải pháp tốt nhất cho vấn đề. Đơn giản chỉ cần xóa bộ nhớ cache của DbContext và bạn tốt để đi. –