C# 在实体框架中更新多对多关系

C# 在实体框架中更新多对多关系,c#,entity-framework,many-to-many,C#,Entity Framework,Many To Many,情况:我有一个类似于标签的东西:用户可以更改某个实体的标签列表。实体和标记具有多对多关系 问题:用户可以添加一些新标签,删除一些旧标签,保留一些标签,而无需更改。例如: 之前:a、b、c 在:b,c,d之后 标签a已删除,标签d已添加。通过最小化SQL查询的数量,最有效的方法是什么 可能的解决方案: 我找到了两种解决方案,但我认为它们并不好 删除所有旧标记并添加新标记 // entityId - editing entity's id // tagIds - new tags ids

情况:我有一个类似于标签的东西:用户可以更改某个实体的标签列表。实体和标记具有多对多关系

问题:用户可以添加一些新标签,删除一些旧标签,保留一些标签,而无需更改。例如:

  • 之前:a、b、c
  • 在:b,c,d之后
标签
a
已删除,标签
d
已添加。通过最小化SQL查询的数量,最有效的方法是什么

可能的解决方案

我找到了两种解决方案,但我认为它们并不好

  • 删除所有旧标记并添加新标记

    // entityId - editing entity's id
    // tagIds   - new tags ids
    
    var entity _entityRepository.GetAll()
         .Include(x => x.Tags)
         .FirstOrDefault(x => x.Id == entityId);
    entity.Tags.RemoveAll();
    
    // Add new tags
    entity.Tags = _tagsRepository.GetAll()
         .Where(x => tagIds.Contains(x.Id)); //Yes, this .Contains works
    
    _entityRepository.Update(entity);
    
  • 将旧的标记列表与新的标记列表进行比较,并添加或删除以使它们等效

    // entityId - editing entity's id
    // tagIds   - new tags ids
    
    var entity _entityRepository.GetAll()
         .Include(x => x.Tags)
         .FirstOrDefault(x => x.Id == entityId);
    
     // Add tags which not exists in entity.Tag
     foreach (var tagId in tagIds)
     {
         if (!entity.Tags.Any(x => x.Id == tagId))
         {
             //A lot of queiries!
             var newTag = _tagsRepository.GetAll()
                     .FirstOrDefault(x => x.Id == tagId);
             entity.Tags.Add(newTag);
         }
     }
    
     // Remove tags whic not exists in tagIds
     // Assuming Tags is IList<T> and we can use []
     int i = 0;
    
     while (i < entity.Tags.Count)
     {
         if (!tagIds.Contains(entity.Tags[i].Id))
             entity.Tags.RemoveAt(i);
         else
             i++;
     }
    
     _entityRepository.Update(entity);
    
    //entityId-编辑实体的id
    //标记ID-新标记ID
    var实体_entityRepository.GetAll()
    .Include(x=>x.Tags)
    .FirstOrDefault(x=>x.Id==entityId);
    //添加实体.Tag中不存在的标记
    foreach(tagId中的var tagId)
    {
    if(!entity.Tags.Any(x=>x.Id==tagId))
    {
    //很多地方!
    var newTag=_tagsRepository.GetAll()
    .FirstOrDefault(x=>x.Id==tagId);
    实体.Tags.Add(newTag);
    }
    }
    //删除标记ID中不存在的标记
    //假设标签是IList,我们可以使用[]
    int i=0;
    而(i
  • 解决方案的利弊

    第一个解决方案优点:

    • 很少有SQL查询
    第一种解决方案的缺点是:

    • 移除所有关系并创建新关系,无论它们是否发生变化
    • 使用
      Include
      加载所有
      标记
    第二种解决方案优点:

    • 否全部删除
    第二个解决方案是:

    • 为加载每个新标记进行了大量查询
    • 使用
      Include
      加载所有
      标记

    这个问题的最佳解决方案是什么?

    不要比较任何东西,不要实现检查哪些标志被删除,哪些标志被添加的“逻辑”


    相反,只需为实体指定一个新的标记列表,并告诉实体框架保存对象。它将自行确定哪些必须删除,哪些需要添加。

    出于好奇,当您只有
    tagid
    列表时,这是如何工作的?如何获得分配给实体*的新标记列表?如果您创建了一个包含新标记对象的列表,并且只分配了Id属性,那么我的测试显示EF尝试插入标记记录和链接记录。我做了一些测试,知道这一点:1。您加载标签集合并分配新集合-它可以工作。2-您没有加载旧集合并分配新集合-结果将是两个集合的关联。@Alexeymarov为完整起见,您是否可以使用基于此答案的工作实现(例如选项3)更新您的帖子(或发布自我答案),并进行与1和2相同的分析/比较。