2014-09-29 85 views
0

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

我剥离下来的问题类是

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

通完整的标签为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; 
} 
+0

但是在那个阶段我没有完整的标签。有点像Stackoverflow时,用户添加标签问题我只有标签字符串/文本。 – 2014-09-29 18:48:03

+0

@QaiserIftikhar你不需要完整的标签。如果是新标签,你可以在javascript中创建一个标签对象,默认为零。 – 2014-09-29 18:49:47

+0

对不起,不知道你的意思。我从用户那里得到的是一个带有特定字段的表单,例如问题主体,标题,标签。我收到的标签文本类似于wpf,c#,mvc,java。我用逗号分隔标签文本,然后根据文本询问我的上下文以查看数据库中的标签。在那个阶段,我如何创建一个完整的标签而不是首先检索与用户输入的标签匹配的标签列表? – 2014-09-29 18:54:44

1

尝试使用包括方法,让EF管理你的关系。

public void AddOrRemoveTags(IList<string> tags, Question question) 
 
{ 
 
    var dbQuestion = _context.Questions.Include(a => a.Tags).SingleOrDefault(a => a.QuestionId == question.QuestionId); 
 
\t 
 
    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(); 
 
\t \t   
 
    } 
 
}

新记录:

public void AddTags(IList<string> tags, Question question) 
 
{  \t 
 
    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()整个列表和.toLower()t.Text,这将转换为SQL。

+1

当我需要更新问题时,您的答案是有效的,但我试图解决的第一个问题是用户使用x个标签添加了一个新问题。话虽如此,它仍然是我想要的太多代码,可以用某种通用的方式来做。 – 2014-09-29 22:16:41

+0

我的编辑添加了对你有用的东西吗? – Jarga 2014-09-29 23:18:23