2011-07-26 54 views
8

我得到一個主鍵衝突錯誤,當我嘗試了許多一對多的關係添加項目:與許多一對多的關係在實體框架中添加項目

我有兩個類 - 文章和其中有許多一對多關係標籤:

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; } 
} 

當我添加一個新的文章我允許用戶輸入任何標籤,然後我想創建一個新的標籤,如果尚未創建標籤如果標籤已存在,則將該標籤添加到Article對象的Tags集合中。

因此,當我創建新的Article對象我叫下面的功能:

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 
      } 

     } 

這個功能基本上會檢查是否在數據庫中可用的標籤,如果是返回一個標籤,然後將其添加到Article對象的Tag集合使用article.Tags.Add()。

然而,當我嘗試這個使用下面的代碼保存我得到PRIMARY KEY約束錯誤的違規

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

我想不出我應該怎麼去只是創建文章之間的關係和已經存在的標籤。

+0

請問您能否提供更多的細節和完整的代碼? –

回答

14

使用爲您的操作和生活的整個處理相同的上下文實例將容易得多:

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(); 
} 

如果如果您不想從數據庫中加載文章(如果知道該文章存在,則該查詢是多餘的),您可以使用:

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

謝謝你做到了。我想通過使用不同的上下文,許多人會在實體框架上絆倒。問題是,在同一個操作中做所有事情都會違揹我們通常用不同的操作編程DAL的方式。最好的辦法似乎是將上下文作爲ref參數傳遞。 – Judo

+0

@Judo這就是爲什麼我問你「所以確保當你從代碼中檢索數據庫中的標記時,你正在使用與調用SaveChanges時使用的數據環境相同的數據環境」 –

+0

只需要注意,因爲我在這裏偶然發現 - 如果你're **抽象Repository模式背後的上下文**確保您可以正確**通過注入/工廠**共享上下文。但是如果你跨方法/範圍共享上下文,你可能會遇到一些問題,其中失敗的提交會破壞後續不相關的提交** - 像這樣的「undo」方法可以提供幫助嗎? http://rundevrun.blogspot.com/2012/06/entity-framework-removing-failed.html – drzaus

0

你如何去創建新的標籤?以及如何將現有或創建的實體附加到文章中。

使用類似

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

閱讀這篇文章http://thedatafarm.com/blog/data-access/inserting-many-to-many-relationships-in-ef-with-or-without-a-join-entity/

+0

如果標籤存在,我只需使用article.Tag.Add(existingTag)添加它。但是,當我嘗試保存它會拋出主鍵違規錯誤。 – Judo

+0

當它是一個現存的標籤時,你需要讓框架知道它是一個存在的實體。該框架試圖再次插入實體。 請確保您已在主鍵上設置標識列。 –

+0

好吧,那麼我該如何讓框架知道它現有的實體? – Judo