首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实体框架6多对多插入更新

实体框架6多对多插入更新
EN

Stack Overflow用户
提问于 2014-09-30 02:12:13
回答 2查看 1.2K关注 0票数 0

我正在开发一个使用asp.net mvc,ef6的问答软件。我试图解决的问题之一是插入/更新多对多项。例如,如果用户提出一个问题并添加标签,他们可以选择现有的标签或创建新的标签。

我精简的问题类是

代码语言:javascript
复制
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; }
    }
}

我的标记类是这样的

代码语言:javascript
复制
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; }
    }
}

我的上下文是这样的

代码语言:javascript
复制
public class MyDbContext
        : DbContext
{
    public virtual DbSet<Tag> Tags { get; set; }
    public virtual DbSet<Question> Questions { get; set; }
}

当我需要保存带有标签的问题时,我必须手动检查用户添加到问题中的标签是否存在。如果它们不存在,我会创建它们并保存上下文,然后返回标签并将其添加到问题中。我想知道在EF6中有没有更好的方法来做这样的事情?

我的示例代码如下

代码语言:javascript
复制
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;
}
EN

回答 2

Stack Overflow用户

发布于 2014-09-30 06:00:03

尝试使用Include方法,让EF为您管理关系。

代码语言:javascript
复制
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();
		       
   }
}

对于新记录:

代码语言:javascript
复制
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 });
    }

  }
}

然后,您需要将问题对象添加到更高级别的上下文中。这应该添加所有相关的引用,并且只需进行一次小旅行就可以获得您所关心的标签。重要的一点是,您不能以这种方式从数据库中提取整个标记集。

注意:如果你关心大小写,你可以对整个列表使用.toLower(),对t.Text使用.toLower(),这样就可以转换成sql。

票数 1
EN

Stack Overflow用户

发布于 2014-09-30 02:42:11

将完整的标签传入CreateOrRetrieveTags方法,然后可以通过Id过滤来识别新的标签:

代码语言:javascript
复制
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;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26106185

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档