2011-07-26 31 views
8

Tôi gặp phải lỗi vi phạm chính khi cố gắng thêm mục có mối quan hệ nhiều-nhiều:Thêm mục có nhiều mối quan hệ vào khung thực thể

Tôi có hai lớp - Bài viết và thẻ mà có một mối quan hệ nhiều-nhiều:

public class Article 
{ 
    public int ID { get; set; } 
    public string Text { get; set; } 
    public ICollection<Tag> Tags { get; set; } 
} 

public class Tag 
{ 
    [Key] 
    public string UrlSlug { get; set; } 
    public string Name { get; set; } 
    public ICollection<Article> Articles{ get; set; } 
} 

Khi tôi thêm một Điều mới, tôi cho phép người dùng nhập vào bất kỳ thẻ và sau đó tôi muốn tạo một khóa mới nếu Tag chưa được tạo trong cơ sở dữ liệu hoặc thêm Thẻ vào bộ sưu tập Thẻ của đối tượng Bài viết nếu Thẻ đã tồn tại.

Do đó khi tôi đang tạo ra các đối tượng Điều mới tôi gọi là chức năng dưới đây:

public static Tag GetOrLoadTag(String tagStr) 
     { 
      string tagUrl = Tag.CreateTagUrl(tagStr); 
      var db = new SnippetContext(); 
      var tagFromDb = from tagdummy in db.Tags.Include(x => x.Articles) 
          where tagdummy.UrlSlug == tagUrl 
          select tagdummy; 
      if (tagFromDb.FirstOrDefault() != null) 
      { return tagFromDb.FirstOrDefault(); } 
      else 
      { 
       //create and send back a new Tag 
      } 

     } 

Chức năng này về cơ bản sẽ kiểm tra nếu có một Tag có sẵn trong cơ sở dữ liệu và nếu như vậy trả rằng Tag mà sau đó sẽ được thêm vào bộ sưu tập Thẻ của đối tượng Bài viết bằng cách sử dụng article.Tags.Add().

Tuy nhiên, khi tôi cố gắng để tiết kiệm này bằng cách sử dụng đoạn mã sau tôi nhận được một Vi phạm PRIMARY KEY lỗi khó khăn

db.Entry(article).State = EntityState.Modified; 
db.SaveChanges(); 

Tôi không thể hiểu làm thế nào tôi nên đi về chỉ tạo ra một mối quan hệ giữa Điều và Thẻ đã tồn tại.

+0

bạn có thể vui lòng cung cấp thêm chi tiết và mã đầy đủ không? –

Trả lời

14

Sử dụng ví dụ hoàn cảnh tương tự cho toàn bộ xử lý hoạt động của bạn và cuộc sống của bạn sẽ dễ dàng hơn:

using (var ctx = new MyContext()) 
{ 
    Article article = ctx.Articles.Single(a => a.Id == articleId); 
    Tag tag = ctx.Tags.SingleOrDefault(t => t.UrlSlug == tagUrl); 
    if (tag == null) 
    { 
     tag = new Tag() { ... } 
     ctx.Tags.AddObject(tag); 
    } 

    article.Tags.Add(tag); 
    ctx.SaveChanges(); 
} 

Nếu bạn không muốn tải bài viết từ cơ sở dữ liệu (truy vấn đó thừa nếu bạn biết bài viết đó tồn tại) bạn có thể sử dụng:

using (var ctx = new MyContext()) 
{ 
    Article article = new Article() { Id = articleId }; 
    ctx.Articles.Attach(article); 

    Tag tag = ctx.Tags.SingleOrDefalut(t => t.UrlSlug == tagUrl); 
    if (tag == null) 
    { 
     tag = new Tag() { ... } 
     ctx.Tags.AddObject(tag); 
    } 

    article.Tags.Add(tag); 
    ctx.SaveChanges(); 
} 
+0

Cảm ơn điều đó đã làm các trick. Tôi đoán rất nhiều người bị vấp phải trên Entity Framework bằng cách sử dụng một Context khác. Vấn đề là làm mọi thứ trong cùng một loại hoạt động đi ngược lại cách chúng ta thường lập trình một DAL với các hoạt động khác nhau. Việc đặt cược tốt nhất dường như là đi qua bối cảnh như một tham số ref. – Judo

+0

@Judo đó là lý do tại sao tôi hỏi bạn "Vì vậy, hãy chắc chắn rằng khi bạn đang lấy thẻ từ db trong mã của bạn, bạn đang sử dụng cùng một datacontext như bạn đang sử dụng khi gọi SaveChanges" –

+0

Chỉ cần lưu ý, kể từ khi tôi stumbled đây - nếu bạn 'lại ** tóm tắt ngữ cảnh đằng sau mẫu Repository ** đảm bảo rằng bạn có thể ** chia sẻ ngữ cảnh một cách chính xác thông qua injection/factory **. Nhưng nếu bạn chia sẻ ngữ cảnh qua các phương thức/phạm vi, bạn có thể gặp phải các vấn đề trong đó ** không cam kết phá vỡ các cam kết không liên quan tiếp theo ** - điều gì đó giống như phương thức "hoàn tác" này có thể hữu ích? http://rundevrun.blogspot.com/2012/06/entity-framework-removing-failed.html – drzaus

0

Bạn làm cách nào để tạo thẻ mới? Và làm thế nào để bạn đính kèm thực thể hiện có hoặc tạo ra cho bài viết.

Sử dụng một cái gì đó giống như

Article a = new Article(...); 
a.tags.add(GetOrLoadTag("some tag")); 

Đọc bài viết này http://thedatafarm.com/blog/data-access/inserting-many-to-many-relationships-in-ef-with-or-without-a-join-entity/

+0

Nếu Thẻ tồn tại, tôi chỉ cần thêm nó bằng cách sử dụng article.Tag.Add (existingTag). Nhưng khi tôi cố gắng để lưu nó ném lỗi vi phạm chính tiểu học. – Judo

+0

Khi đó là một thẻ có sẵn, bạn cần phải cho phép khung công tác biết đó là một thực thể tồn tại. Khung công tác đang cố chèn lại thực thể. Và hãy đảm bảo bạn đã đặt cột nhận dạng trên khóa chính. –

+0

Ok, vậy làm thế nào để tôi biết khuôn khổ đó biết thực thể hiện tại của nó? – Judo

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