我正在使用asp.net mvc,ef6处理问题/答案软件。我试图解决的问题之一是插入/更新许多项目。例如,如果用户提出问题并为其添加标记,他们可以选择现有标记或创建新标记。
我被剥离的问题类是
public class Question
{
private ICollection<Tag> _tags;
public long Id { get; set; }
public string Body { get; set; }
public virtual ICollection<Tag> Tags
{
get { return _tags ?? (_tags = new Collection<Tag>()); }
set { _tags = value; }
}
}
我的标签类就像
public class Tag
{
private ICollection<Question> _questions;
public long Id { get; set; }
public string Text { get; set; }
public virtual ICollection<Question> Questions
{
get { return _questions?? (_questions=new Collection<Question>()); }
set { _questions = value; }
}
}
我的背景是这样的
public class MyDbContext
: DbContext
{
public virtual DbSet<Tag> Tags { get; set; }
public virtual DbSet<Question> Questions { get; set; }
}
当我需要用标签保存问题时,我必须手动检查用户已添加到问题的标签是否存在。如果它们不存在,我创建它们并保存上下文,然后返回标记并将它们添加到问题中。我想知道在EF6中是否有更好的方法来做这样的事情?
我的示例代码如下
public IEnumerable<Tag> CreateOrRetrieveTags(IList<string> tags)
{
List<string> availableTags = (from t in _context.Tags
where tags.Contains(t.Text)
select t.Text).ToList();
var missingTags = tags.Except(availableTags, StringComparer.OrdinalIgnoreCase);
foreach (string missingTag in missingTags)
{
_context.Tags.Add(new Tag
{
Text = missingTag
});
}
_context.SaveChanges();
return from t in _context.Tags
where tags.Contains(t.Text)
select t;
}
答案 0 :(得分:1)
尝试使用Include方法,让EF为您管理关系。
public void AddOrRemoveTags(IList<string> tags, Question question)
{
var dbQuestion = _context.Questions.Include(a => a.Tags).SingleOrDefault(a => a.QuestionId == question.QuestionId);
if (dbQuestion != null)
{
var remainingTags = new List<string>(tags);
var tagsToRemove = dbQuestion.Tags.Where(t => !tags.Contains(t.Text, StringComparer.OrdinalIgnoreCase)).ToList();
foreach (var tag in tagsToRemove)
{
dbQuestion.Tags.Remove(tag);
remainingTags.remove(tag.Text);
}
foreach(var remainingTag in remainingTags){
dbQuestion.Tags.Add(new Tag(){ Text = remainingTag });
}
_context.SaveChanges();
}
}
对于新记录:
public void AddTags(IList<string> tags, Question question)
{
if (question != null)
{
var existingTags = _context.Tags.Where(t => tags.ToArray().Contains(t.Text)).ToList()
var remainingTags = new List<string>(tags);
foreach (var tag in existingTags)
{
question.Tags.Add(tag);
remainingTags.remove(tag.Text);
}
foreach(var remainingTag in remainingTags){
question.Tags.Add(new Tag(){ Text = remainingTag });
}
}
}
然后您需要将您的Question对象添加到更高级别的上下文中。这应该添加所有相关的引用,并且只进行一次小的旅行以获得您关心的标记。一个重要的部分是,您不会以这种方式从数据库中提取整个标记集。
注意:如果你关心区分大小写,你可以.toLower()整个列表和.toLower()t.Text,这将转换为sql。
答案 1 :(得分:0)
将完整标记传递给CreateOrRetrieveTags方法,然后您可以按ID过滤以识别新标记:
public List<Tag> CreateOrRetrieveTags(List<Tag> tags)
{
var newTags = tags.Where(t => t.Id == 0);
foreach (string newTag in newTags)
{
_context.Tags.Add(newTag);
}
_context.SaveChanges();
return from t in _context.Tags
where tags.Any(t.Text == t.Text)
select t;
}