0

這個想法很簡單。我有一個標籤列表。當我創建一個問題時,我想添加一些標籤。多對多的關係 - 我做對了嗎?

型號:

public class QuestionModel 
{ 
    public int Id { get; set; } 

    public String Content { get; set; } 

    public ICollection<TagModeltoQuestionModel> Tags { get; set; } 

    [NotMapped] 
    public ICollection<TagModel> AssignedTags { get { return Tags.Select(x => x.Tag).ToList(); } } 

    public int UserId { get; set; } 
} 

public class QuestionViewModel // helper - not in database 
{ 
    public QuestionModel Model { get; set; } 
    public ICollection<TagModel> Tags { get; set; } 
} 

public class TagModel 
{ 
    public int Id { get; set; } 

    public String Name { get; set; } 

    public ICollection<TagModeltoQuestionModel> Questions { get; set; } 

    [NotMapped] 
    public bool Assigned { get; set; } 

    [NotMapped] 
    public ICollection<QuestionModel> AssignedQuestions { get { return Questions.Select(x => x.Question).ToList(); } } 

} 

public class TagModeltoQuestionModel // many to many 
{ 
    [Key, Column(Order = 0)] 
    public int TagId { get; set; } 
    [Key, Column(Order = 1)] 
    public int QuestionId { get; set; } 

    public virtual QuestionModel Question { get; set; } 
    public virtual TagModel Tag { get; set; } 
} 

控制器:

[HttpPost] 
public ActionResult Edit(QuestionViewModel questionViewModel) 
{ 
    if (ModelState.IsValid) 
    { 
     _repo.Update(questionViewModel.Model, questionViewModel.Tags); // see repo code below 
     return RedirectToAction("Index"); 
    } 
    return View(questionViewModel.Model); 
} 

回購:

public void Update(QuestionModel entity, ICollection<TagModel> tags) 
{ 
    AssignTags(entity, tags); 
    Db.Attach(entity); 
    Db.SaveChanges(); 
} 

private void AssignTags(QuestionModel entity, ICollection<TagModel> tags) 
{ 
    tags = tags.Where(x => x.Assigned).ToArray(); // remove unassigned comming form View --> Controller 

    var linkedTags = 
     Db.TagsToQuestions.Where(x => x.QuestionId == entity.Id); 
    var linkedTagsIds = linkedTags.Select(x => x.TagId); 

    var selectedTagsIds = tags.Select(x => x.Id); 
    var oldTags = linkedTags.Where(x => !selectedTagsIds.Contains(x.TagId)); 
    var newTags = tags.Where(x => !linkedTagsIds.Contains(x.Id)).Select(x=> new TagModeltoQuestionModel{QuestionId=entity.Id,TagId=x.Id}); 

    foreach (var t in oldTags) 
     Db.Delete(t); 

    foreach (var t in newTags) 
     Db.Add(t); 

    Db.SaveChanges(); 
} 

這工作得很好,雖然我不知道這是去(正道實際上我自己實現了整個多對多邏輯)。有沒有更聰明的方法讓EF爲我做這份工作?我通過一堆教程挖掘,但沒有一個爲我工作。

此外,我覺得AssignTags方法可以寫得更好,所以任何意見也表示讚賞。

編輯

根據haim770的回答我的簡化模型,他建議的方式。

我的控制器現在看起來像這樣:

public void Update(QuestionModel entity, ICollection<TagModel> tags) 
{ 
    Db.Attach(entity); 

    //these lines give the same result 
    //var ids = tags.Select(y => y.Id).ToArray(); 
    //entity.Tags = Db.Tags.Where(x => ids.Contains(x.Id)).ToArray(); 

    tags.ForEach(x => Db.Attach(x)); 
    entity.Tags = tags; 
    Db.SaveChanges(); 
} 

的SaveChanges導致錯誤:

An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details. 
inner: 
{"A duplicate value cannot be inserted into a unique index. [ Table name = TagModelQuestionModels,Constraint name = PK_TagModelQuestionModels ] 

那麼如何正確地執行呢?

+0

您的問題似乎更適合http://codereview.stackexchange.com StackOverflow是一個編程相關的問答網站,你應該只問問題,你可能會遇到問題遇到一段特定的代碼。 – 2013-03-17 12:18:33

+0

@DarinDimitrov部分你是對的。我可能會問'如何實現一個多對多的關係',因爲這是我的真正意義,但是我包含了更具體的代碼。 – gisek 2013-03-17 12:23:42

+0

好的,那麼你遇到這個代碼有什麼特別的問題?什麼不起作用?你收到了什麼錯誤信息? StackOverflow是一個問答網站,用戶可以詢問關於他們遇到問題的特定代碼的具體問題。那麼你呢?你遇到了什麼問題,這些代碼有什麼不工作?如果您無法回答這些問題,只是要求進行代碼審查或是否有更好的方法來實現某些內容,那麼,正如我在第一條評論中所述,您的問題更適合http://codereview.stackexchange。com/ – 2013-03-17 12:24:19

回答

2

你不需要TagModeltoQuestionModel類。你可以模擬many-to-many關係是這樣的:

public class QuestionModel 
{ 
    //.... 
    public ICollection<TagModel> Tags { get; set; } 
} 

public class TagModel 
{ 
    //.... 
    public ICollection<QuestionModel> Questions { get; set; } 
} 

Question擁有許多Tags參考,每個Tag擁有許多Questions參考。

Entity Framework整點(像任何其他ORM)是不必你的對象和他們的關係模型在database-like的方式,而是讓你它在那麼一個純粹的Object Oriented方式讓ORM模型饒你的「骯髒的工作'的中間表,外鍵等...

+0

這適用於創建操作。崩潰(myQuestion.Tags = someTags)它在SaveChanges()中報告關鍵字(它試圖在myQuestion.Tags中重新添加標籤而不是更新它們) – gisek 2013-03-18 09:47:47

+0

請將完整的異常和「更新」代碼一起發佈 – haim770 2013-03-18 10:30:36

+0

另外,我並不是說按照我推薦的方式改變你的實體應該立即使它工作,我只是簡單介紹了它應該完成的方式。 在你的情況中,在你改變你的類之後,你是否改變了數據庫相應地,您是否讓實體框架爲您重新創建了它? – haim770 2013-03-18 10:49:06