这个想法很简单。我有一个标签列表。当我创建一个问题时,我想添加一些标签。多对多的关系 - 我做对了吗?
型号:
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 ]
那么如何正确地执行呢?
您的问题似乎更适合http://codereview.stackexchange.com StackOverflow是一个编程相关的问答网站,你应该只问问题,你可能会遇到问题遇到一段特定的代码。 – 2013-03-17 12:18:33
@DarinDimitrov部分你是对的。我可能会问'如何实现一个多对多的关系',因为这是我的真正意义,但是我包含了更具体的代码。 – gisek 2013-03-17 12:23:42
好的,那么你遇到这个代码有什么特别的问题?什么不起作用?你收到了什么错误信息? StackOverflow是一个问答网站,用户可以询问关于他们遇到问题的特定代码的具体问题。那么你呢?你遇到了什么问题,这些代码有什么不工作?如果您无法回答这些问题,只是要求进行代码审查或是否有更好的方法来实现某些内容,那么,正如我在第一条评论中所述,您的问题更适合http://codereview.stackexchange。com/ – 2013-03-17 12:24:19