【发布时间】:2013-03-17 12:08:19
【问题描述】:
这个想法很简单。我有一个标签列表。当我创建一个问题时,我想给它添加一些标签。
型号:
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 方法可以用更好的方式编写,因此任何与此相关的 cmets 也很感激。
编辑
根据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 ]
那么如何正确实现呢?
【问题讨论】:
-
您的问题似乎更适合codereview.stackexchange.com * 是一个与编程相关的问答网站,您应该只针对特定代码可能遇到的问题提出特定问题。
-
@DarinDimitrov 部分你是对的。我本来可以问“如何实现多对多关系”,因为这是我的真正意思,但我包含了更具体的代码。
-
好的,那么您在使用这段代码时遇到了什么特殊问题?什么不工作?你得到什么错误信息? * 是一个问答网站,人们可以在其中询问有关他们遇到问题的特定代码的特定问题。那你呢?您在使用此代码时遇到了哪些问题,哪些问题不起作用?如果您无法回答这些问题而只是要求进行代码审查或者是否有更好的方法来实现某些东西,那么,正如我在第一条评论中已经说过的那样,您的问题更适合codereview.stackexchange.com
-
@DarinDimitrov 我的代码问题是只有 QuestionModel 和 TagModel 都有彼此的集合(没有 TagModeltoQuestionModel)。这根本行不通——没有工作关系。我使用 TagModeltoQuestionModel 作为解决方法并将其发布以表明我在问题上付出了一些努力。还不符合条件吗? :(
-
我引用你的问题:
This works fine。所以我重复我的问题:What problems did you encounter with your code? What errors or exceptions did you encounter?.
标签: c# asp.net-mvc entity-framework asp.net-mvc-4 ef-code-first