2012-05-10 32 views
8

Tôi đã làm việc với các dịch vụ RIA, nơi ObjectContext có phương thức RejectChanges(). Tuy nhiên, tôi hiện đang làm việc với EF 4.4 trong một ứng dụng máy tính để bàn và tôi không thể tìm thấy phương pháp đó. Vì vậy, câu hỏi của tôi là: trong một scenrario, nơi tôi cho phép người dùng thực hiện các thao tác Crud batch trên bộ sưu tập, làm thế nào tôi có thể hoàn nguyên tất cả các thay đổi? Tôi có thể đi với tái tạo bối cảnh và lấy dữ liệu một lần nữa, nhưng âm thanh đó rất cần thiết nếu tôi cần phải hoàn nguyên các thay đổi trở lại 1-2 thực thể.DbContext và RejectChanges

Vì vậy, cách tốt nhất để từ chối thay đổi là gì? Và cũng có thể, làm cách nào để chúng ta biết liệu bối cảnh có đang làm điều gì đó (IsBusy)?

Trả lời

11

EF không có bất kỳ hoạt động "từ chối thay đổi" trực tiếp nào. Bạn có thể đi qua các mục nhập thực thể trong ChangeTracker/ObjectStateManager và ghi đè các giá trị hiện tại với các giá trị gốc cho các thực thể được sửa đổi. Bạn cũng có thể tách các thực thể được thêm và thay đổi các thực thể đã xóa thành không thay đổi nhưng tất cả sẽ chỉ hoạt động nếu bạn (hoặc EF nội bộ) không thay đổi trạng thái của bất kỳ liên kết độc lập nào (quan hệ). Nếu bạn làm việc với các mối quan hệ cũng như toàn bộ điều có thể trở nên phức tạp hơn nhiều vì bạn phải hoàn nguyên các mối quan hệ - trong trường hợp đó, việc tải lại dữ liệu trở nên đơn giản hơn.

Đối với hoàn nguyên thay đổi trong DbContext API bạn có thể thử này:

foreach (var entry in context.ChangeTracker 
          .Entries<YourEntityType>() 
          .Where(e => e.State == EntityState.Modified)) 
{ 
    entry.CurrentValues.SetValues(entry.OriginalValues); 
} 

Trong trường hợp này tôi nghĩ rằng vấn đề chính là cách làm thế nào bạn làm việc với các đơn vị - bạn cho phép thay đổi nào trên dữ liệu trực tiếp và EF không logic của nó phía sau để giữ cho dữ liệu nhất quán khi thay đổi được thực hiện nhưng sau đó bạn quyết định rằng những thay đổi đó sẽ không được lưu. Trong trường hợp này bạn nên làm một trong sau:

  • Huỷ thay đổi dữ liệu và tải lại toàn bộ dữ liệu (bằng cách tái tạo ngữ cảnh)
  • riêng logic này để không làm việc trên dữ liệu trực tiếp và đẩy sửa đổi dữ liệu để chỉ EF bối cảnh khi sửa đổi thực sự được xác nhận

Bối cảnh đang làm điều gì đó nếu bạn nói nó làm điều gì đó. Nó không bao giờ trở nên bận rộn.

+0

Tạo lại ngữ cảnh sẽ là một giải pháp tốt. Tuy nhiên, tôi đã gặp sự cố khi đồng bộ hóa dữ liệu liên quan. Một ví dụ là tôi đã có CRUD trên CollectionA trên ViewA và CRUD trên COllectionB trên ViewB. CollectionB cũng giữ tham chiếu đến CollectionA. Vì vậy, nếu tôi có 2 đối tượng Context, cả cho CollectionA và CollectionB, tôi sẽ đồng bộ hóa ViewB như thế nào, nếu tôi thay đổi CollectionA trên ViewA? Khi có một Context mọi thứ đều đồng bộ, vì chúng ta đang thực sự chỉ làm việc trên một collectionA, không phải là hai. Tái tạo bối cảnh "toàn cầu" sẽ tạo ra một mớ hỗn độn. :) Tôi đã nhầm lẫn bằng cách sử dụng ngữ cảnh "toàn cầu" chưa? – Goran

+0

Đối với các "bận rộn", tôi đã quan tâm những gì sẽ xảy ra nếu tôi phát hành một Load trong async maner, và sau đó tôi cố gắng phát hành một Load, trong khi trước đó đã không kết thúc? Bằng cách này tôi có thể kiểm tra nếu nó là "bận rộn", vì vậy tôi có thể xếp hàng một Load mới. – Goran

+0

+1 để nhận thấy điều mà hầu hết mọi người dường như bỏ lỡ. các mối quan hệ: có thể có các thay đổi được theo dõi sẽ không được chọn đơn giản bằng cách xem qua bộ sưu tập Entries cho State! = Unchanged. (EF v6.) – mwardm

1

này làm việc cho tôi:

public void RejectChanges() { 
    var context = ((IObjectContextAdapter)this).ObjectContext; 
    foreach (var change in this.ChangeTracker.Entries()) { 
     if (change.State == EntityState.Modified) { 
      context.Refresh(RefreshMode.StoreWins, change.Entity); 
     } 
     if (change.State == EntityState.Added) { 
      context.Detach(change.Entity); 
     } 
    } 
} 

này = DbContext trong trường hợp này

+1

Điều gì về các thực thể đã bị xóa? Ngoài ra, làm thế nào bạn sẽ nhận được dữ liệu mới cho các thực thể được thay đổi bởi những người dùng khác, phải không? – Goran

2

Tôi biết đây là một câu hỏi cũ. Tuy nhiên, không có câu trả lời nào phù hợp với hoàn cảnh của tôi. Tôi cần từ chối các thay đổi trên chỉ 1 thực thể trong bộ sưu tập. Đây là những gì làm việc cho tôi:

var objectContext = (myDbContext as IObjectContextAdapter).ObjectContext; 
    objectContext.Refresh(RefreshMode.StoreWins, partMaster); 
+0

Mặc dù câu hỏi về thay đổi bộ sưu tập, không phải là thực thể duy nhất, tôi không thấy câu trả lời nào không giúp bạn? Câu trả lời ngay phía trên của bạn (TheSoul75) thực hiện chính xác giống như bạn đang gợi ý, chỉ có nó cho tất cả các mục trong bộ sưu tập. – Goran

+0

Goran, nếu tất cả thay đổi trong bộ sưu tập bị từ chối thì dữ liệu của tôi sẽ không hợp lệ. Chỉ một trong các mục trong bộ sưu tập cần hoàn nguyên về giá trị ban đầu. Tôi cần một cách tiếp cận chi tiết hơn. Tôi biết đôi khi những người khác cũng cần kiểm soát chi tiết. Tôi đã đăng câu trả lời để giúp những người khác có yêu cầu tương tự. – Tarzan

+1

Vâng, bạn không sử dụng foreach, nhưng về cơ bản bạn đang sử dụng cùng một techicque (Làm mới với StoreWins), vì vậy tôi không thấy giá trị gia tăng trong câu trả lời của bạn, vì bạn vừa xóa vòng lặp. – Goran

11
public void RejectChanges() 
     { 
      foreach (var entry in ChangeTracker.Entries()) 
      { 
       switch (entry.State) 
       { 
        case EntityState.Modified: 
         { 
          entry.CurrentValues.SetValues(entry.OriginalValues); 
          entry.State = EntityState.Unchanged; 
          break; 
         } 
        case EntityState.Deleted: 
         { 
          entry.State = EntityState.Unchanged; 
          break; 
         } 
        case EntityState.Added: 
         { 
          entry.State = EntityState.Detached; 
          break; 
         } 
       } 
      } 
     } 
+0

Điều này có vẻ là câu trả lời duy nhất xử lý tất cả các tiểu bang mà không cần nhấn cơ sở dữ liệu. +1 – Dan

+0

Nếu tôi chỉ thay đổi tài liệu tham khảo thì sao? Đặc biệt tinh khiết m: n khi không có bất kỳ tài sản quan trọng nước ngoài bị ảnh hưởng? – springy76

0

Đây có thể là một câu trả lời cũ nhưng hữu ích cho bất kỳ du khách mới .... Chức năng Nạp lại sẽ được tải lại các đối tượng từ các nguồn dữ liệu và ghi đè lên bất kỳ thay đổi hiện có và thực thể mới được tải sẽ có trạng thái không thay đổi.

public static void UndoEntityChanges(object Entity) 
{ 
    <EFModelContainer>.Entry(Entity).Reload(); 
} 
Các vấn đề liên quan