2011-03-21 54 views
7

Giả sử, tôi có mô hình khái niệm sau đây, có các tầng có thẻ (nhiều hơn một, vì vậy đó là mối quan hệ nhiều-nhiều), cộng với mỗi thẻ thuộc về một danh mục cụ thể.Khuôn khổ thực thể: Tránh chèn trùng lặp

Dữ liệu của tôi đến từ một nguồn bên ngoài và trước khi chèn nó, tôi muốn đảm bảo rằng không có thẻ trùng lặp nào được thêm vào.

Cập nhật đoạn mã:

static void Main(string[] args) 
    { 
     Story story1 = new Story(); 
     story1.Title = "Introducing the Entity Framework"; 
     story1.Tags.Add(new Tag { Name = ".net", }); 
     story1.Tags.Add(new Tag { Name = "database" }); 

     Story story2 = new Story(); 
     story2.Title = "Working with Managed DirectX"; 
     story2.Tags.Add(new Tag { Name = ".net" }); 
     story2.Tags.Add(new Tag { Name = "graphics" }); 

     List<Story> stories = new List<Story>(); 
     stories.Add(story1); 
     stories.Add(story2); 

     EfQuestionEntities db = new EfQuestionEntities(); 

     Category category = (from c in db.Categories 
          where c.Name == "Programming" 
          select c).First(); 

     foreach (Story story in stories) 
     { 
      foreach (Tag tag in story.Tags) 
      { 
       Tag currentTag = tag; 
       currentTag = GetTag(tag.Name, category, db); 
      } 

      db.Stories.AddObject(story); 
     } 

     db.SaveChanges(); 
    } 

    public static Tag GetTag(string name, Category category, EfQuestionEntities db) 
    { 
     var dbTag = from t in db.Tags.Include("Category") 
        where t.Name == name 
        select t; 

     if (dbTag.Count() > 0) 
     { 
      return dbTag.First(); 
     } 

     var cachedTag = db.ObjectStateManager.GetObjectStateEntries(EntityState.Added). 
      Where(ose => ose.EntitySet == db.Tags.EntitySet). 
      Select(ose => ose.Entity). 
      Cast<Tag>().Where(x => x.Name == name); 

     if (cachedTag.Count() != 0) 
     { 
      return cachedTag.First(); 
     } 

     Tag tag = new Tag(); 
     tag.Name = name; 
     tag.Category = category; 

     db.Tags.AddObject(tag); 

     return tag; 
    } 

Tuy nhiên, tôi nhận được một ngoại lệ về một đối tượng với các EntityKey cùng đó là đã có trong ObjectContext.

Ngoài ra, nếu tôi xóa câu lệnh khác, tôi sẽ nhận được ngoại lệ về việc vi phạm ràng buộc FK, vì vậy có vẻ như thuộc tính Danh mục của nó được đặt thành rỗng.

Trả lời

4

Tôi đã gặp vấn đề tương tự với EF. Đây là những gì tôi đã kết thúc thực hiện:

  1. Thay vì làm story1.Tags.Add(new Tag { Name = ".net", }) mình, chuyển tất cả Tag tạo thông qua một phương pháp helper như thế này: story1.Tags.Add(GetTag(".net")).
  2. Phương thức GetTag kiểm tra các thẻ trong ngữ cảnh để xem liệu nó có trả về một thực thể hiện tại như bạn không. Nếu có, nó sẽ trả về điều đó.
  3. Nếu không có thực thể hiện tại, nó sẽ kiểm tra ObjectStateManager để xem liệu có Tag đối tượng được thêm vào ngữ cảnh nhưng chưa được ghi vào db hay không. Nếu nó tìm thấy một phù hợp với Tag, nó sẽ trả về điều đó.
  4. Nếu nó vẫn chưa tìm thấy Tag, nó sẽ tạo một Tag mới, thêm nó vào ngữ cảnh và sau đó trả về nó.

Về bản chất, điều này sẽ đảm bảo rằng không quá một phiên bản của bất kỳ Tag (là đã tồn tại hoặc vừa được tạo) sẽ được sử dụng trong suốt chương trình của bạn.

Một số mã ví dụ được nâng cấp từ dự án của tôi (sử dụng InventoryItem thay vì Tag, nhưng bạn có ý tưởng).

Vui lòng cung trong bước 3 được thực hiện như thế này:

// Second choice: maybe it's not in the database yet, but it's awaiting insertion? 
inventoryItem = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added) 
    .Where(ose => ose.EntitySet == context.InventoryItems.EntitySet) 
    .Select(ose => ose.Entity) 
    .Cast<InventoryItem>() 
    .Where(equalityPredicate.Compile()) 
    .SingleOrDefault(); 

if (inventoryItem != null) { 
    return inventoryItem; 
} 

Nếu Tag không được tìm thấy trong bước 3, đây là mã cho bước 4:

inventoryItem = new InventoryItem(); 
context.InventoryItems.AddObject(inventoryItem); 
return inventoryItem; 

Cập nhật:

Nó nên được sử dụng như thế này:

Story story1 = new Story(); 
story1.Title = "Introducing the Entity Framework"; 
story1.Tags.Add(GetTag(".net", category, db)); 
story1.Tags.Add(GetTag("database", category, db)); 
+0

Cảm ơn bạn! Tôi sẽ thử điều đó ngay bây giờ. Bằng cách này, bạn vẫn đang sử dụng EF sau khi hố phải đối mặt như vậy? –

+0

@Mike: Tôi. Không có gì là tôi không thể tìm ra một cách có thể chấp nhận được để giải quyết những nhu cầu khiêm tốn của tôi, và những gì tôi đang sử dụng trước khi EF (SubSonic) thậm chí còn tồi tệ hơn. – Jon

+0

@Jon: Cũng xin cảm ơn đoạn mã đó.Rất tiếc, tôi vẫn nhận được ngoại lệ vi phạm FK đó phải có nghĩa là các thực thể được theo dõi có Danh mục = null –

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