2012-01-09 10 views
5

Tôi đã viết một phương pháp mở rộng để thêm các mục vào (EF) EntityCollection. Tôi đã nhận được một lỗi thú vị, nói rằng bộ sưu tập của tôi về IEnumerable ("mục") đã được sửa đổi, sau vòng lặp đầu tiên trong foreach. Khi tôi chuyển các mục thành items.ToList() (như trong đoạn code dưới đây), nó hoạt động tốt.C# Sửa đổi bí ẩn IEnumerable, cái gì đang sửa đổi IEnumerable của tôi?

Tôi hoàn toàn hiểu rằng việc thực hiện ToList() sẽ tạo ra một bản sao của các mục mà tại đó foreach sẽ hoạt động.

Điều tôi không hiểu là những gì đang sửa đổi IEnumerable khi tôi đang thực hiện một foreach trên nó.

Cập nhật: Bằng cách nào đó, có vẻ như biến mặt hàng giống với biến số sưu tập?

Cập nhật 2: Tôi nghĩ rằng việc thu thập và tổ chức có thể bị ảnh hưởng bởi theo dõi thực thể của EF, nhưng tôi vẫn không hiểu tại sao

Cách sử dụng:

ssp.ServiceAreas.ReplaceCollection(model.ServiceAreas);

Dưới đây là phương pháp khuyến nông của tôi:

public static void AddOrUpdate<TEntity>(this EntityCollection<TEntity> collection, IEnumerable<TEntity> items) 
     where TEntity : EntityObject, IProjectIdentity<int>, new() 
    { 
     foreach (var item in items.ToList()) 
      collection.AddOrUpdate(item); 
    } 

    public static void AddOrUpdate<TEntity>(this EntityCollection<TEntity> collection, TEntity item) 
     where TEntity : EntityObject, IProjectIdentity<int>, new() 
    { 
     if (item.ID > 0 && collection.Any(c => c.ID == item.ID)) 
      collection.Remove(collection.First(c => c.ID == item.ID)); 
     // For now, the Remove NEVER gets hit 

     collection.Add(item); 
    } 
+3

'Remove' sửa đổi nó, do đó, hãy thêm. – vcsjones

+2

@vcsjones Mặc dù đó là sự thật, trong tình huống này nó không phải là đơn giản. –

+1

Có phải 'items == collection' trong trường hợp của bạn không? –

Trả lời

4
collection.Remove(collection.First(c => c.ID == item.ID)); 

bạn đang xóa trong bộ sưu tập bạn đang lặp lại.

+2

nhưng lặp lại là thông qua một bộ sưu tập khác nhau (các mục) – Erix

+0

Thực tế tôi đã bỏ phiếu này nhưng khi thử nó, điều này không gây ra bất kỳ vấn đề nào. –

+0

Thật vậy Erix, Adam, tôi đã cập nhật bài đăng để làm rõ. – sebastiaan

0

Có lẽ EntityCollection không thích khi ai đó tiếp nhận các yếu tố của nó? Vì vậy, khi bạn Thêm vào collection, mục sẽ bị xóa khỏi items.

Hoặc nó có thể là items == collection

1

Tôi tạo ra mẫu mã sau đây:

internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      var one = new List<string> {"Adam", "John"}; 

      var two = new List<string> {"Adam", "Houldsworth"}; 

      one.AddOrUpdate(two); 

      Console.Read(); 
     } 
    } 

    static class Extensions 
    { 
     public static void AddOrUpdate(this IList<string> collection, IEnumerable<string> items) 
     { 
      foreach (var item in items.ToList()) 
       collection.AddOrUpdate2(item); 
     } 

     public static void AddOrUpdate2(this IList<string> collection, string item) 
     { 
      if (collection.Any(c => c == item)) 
       collection.Remove(collection.First(c => c == item)); 

      collection.Add(item); 
     } 
    } 

này hoạt động như bạn mong đợi, không có lỗi. Vì vậy, về bản chất, không có dòng nào gây ra vấn đề.

Điều gì sẽ gây ra vấn đề là nếu bạn gọi trong danh sách trên chính nó:

one.AddOrUpdate(one); 

Vì vậy, từ những gì tôi có thể nhìn thấy, bạn phải gọi phương thức mở rộng này với bộ sưu tập giống như cả hai đối số.

Nếu có, thì cả hai Remove hoặc Add sẽ thay đổi bộ sưu tập và gây ra ngoại lệ này.

+0

Cảm ơn, nhưng điều này làm việc có và không có .ToList() .. đơn giản chỉ vì bộ sưu tập và các mục thực sự là đối tượng khác nhau. Tôi nghĩ rằng đối tượng bộ sưu tập của tôi có thể bị ảnh hưởng bởi cơ chế theo dõi của EF, sẽ cập nhật các bài đăng một lần nữa. :-) – sebastiaan

+0

@sebastiaan Vâng tôi nhận thấy nó hoạt động mà không có 'ToList' cũng vậy, nhưng tôi đã giữ nó tương tự như mã được cung cấp của bạn để chứng minh nơi vấn đề đang đến. –

0

Có thể là mục đầu tiên luôn là một mục mới, và do đó theo mặc định, ID được đặt thành một số giá trị ban đầu. Sau đó nó sẽ được thêm vào bộ sưu tập, cho phép EntityFramework tạo một ID mới và gán nó cho mục được thêm đầu tiên.

Sau đó có thể là EntityCollection cho rằng nó đã thay đổi, bởi vì nó sử dụng ID để sắp xếp hoặc làm điều gì đó khác trong nội bộ. Và do đó hoạt động foreach (có thể sử dụng cùng một danh sách) đưa ra ngoại lệ. Đó cũng là lý do tại sao trường hợp thử nghiệm được chứng minh bởi Adam Houldsworth không đưa ra vấn đề!

0
EntityCollection<Customer> customers = new EntityCollection<Customer>(); 
Customer newCustomer = new Customer() {ID = 0}; 
customers.Add(newCustomer); 
customers.AddOrUpdate(customers);