C# Ef 6.0多对多插入这么多编码。。。为什么?

C# Ef 6.0多对多插入这么多编码。。。为什么?,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,我的问题是为什么ef 6.0不支持忽略重复项 让我们举一个例子: 我有两张桌子 应用程序{id,AppName} AdGroup{id,GroupName} 应用程序与AdGroup之间存在多对多的关系。现在,每次添加带有广告组的应用程序时,我都需要首先执行以下操作以避免重复的密钥插入: 检查应用程序是否已经存在 检查指定的ADGroups是否已存在 找出差异 更新数据库 为了插入一段血淋淋的关系,这似乎需要做很多工作。可以编写sql查询来执行插入中的选择,以确保数据不存在,然后执行插入。它将根

我的问题是为什么ef 6.0不支持忽略重复项

让我们举一个例子: 我有两张桌子

  • 应用程序{id,AppName}
  • AdGroup{id,GroupName}
  • 应用程序与AdGroup之间存在多对多的关系。现在,每次添加带有广告组的应用程序时,我都需要首先执行以下操作以避免重复的密钥插入:

  • 检查应用程序是否已经存在
  • 检查指定的ADGroups是否已存在
  • 找出差异
  • 更新数据库
  • 为了插入一段血淋淋的关系,这似乎需要做很多工作。可以编写sql查询来执行插入中的选择,以确保数据不存在,然后执行插入。它将根据行是否已存在返回0或1

    假设n到n表将被称为Applications\u AdGroup

    然后,插入关系的查询如下(未测试):

    因此,基本上,即使应用程序、adgroup或关系已经存在,它也不会插入任何内容

    一天结束后,将向db.Applications.Add(obj)发出一个简单的调用,然后保存更改。所有的检查都在后台进行,一切正常吗

    这是怎么回事?我只是做错了吗

    编辑 我可以想象以ef的方式进行操作时会出现一些并发问题。在上述4个步骤中的任何一个步骤中,另一个进程都可能插入AdGroup,并且您仍然会遇到重复的密钥错误

    编辑 随函附上地图:

    //Relation between Application and the Parent Group
                modelBuilder.Entity<Applications>()
                    .HasMany<AdGroup>(s => s.Groups)
                    .WithMany(a => a.Applications)
                    .Map(cs =>
                        {
                            cs.MapLeftKey("Application");
                            cs.MapRightKey("AdGroup");
                            cs.ToTable("Application_Groups");
                        });
    
    //应用程序和父组之间的关系
    modelBuilder.Entity()
    .HasMany(s=>s.Groups)
    .WithMany(a=>a.Applications)
    .Map(cs=>
    {
    cs.MapLeftKey(“申请”);
    cs.MapRightKey(“AdGroup”);
    cs.ToTable(“应用程序组”);
    });
    
    编辑 下面是我用来插入关系的代码示例:

    使用(var db=new ARContext()) {

    var val=新应用程序
    {
    Application=“CRM”,
    组=新列表{
    新的AdGroup{Group=“CRM_ADMIN”},
    新的AdGroup{Group=“CRM_-1”},
    新的AdGroup{Group=“CRM_-2”},
    }
    };
    var dbArr=db.Applications.Where(a=>a.Application==val.Application).FirstOrDefault();
    if(dbArr==null)
    {
    添加(新应用程序(){Application=val.Application});
    db.SaveChanges();
    }
    dbArr=db.Applications.Where(a=>a.Application==val.Application).FirstOrDefault();
    if(dbArr.Groups==null)
    {
    dbArr.Groups=新列表();
    }
    foreach(变量组中的变量gr)
    {
    var dbGrp=db.Groups.Where(g=>g.Group==gr.Group).FirstOrDefault();
    if(dbGrp==null)
    {
    dbArr.Groups.Add(gr);
    }
    其他的
    {
    dbArr.Groups.Add(dbGrp);
    }
    }
    db.SaveChanges();
    
    }

    上面使用的名称和代码示例有一些不同之处,但要点是

    因此,首先我需要保存新的应用程序,然后通过各个组查看它们是否存在,并相应地添加到上下文中。这是除了编写存储过程之外的唯一方法吗


    谢谢

    像这样的东西也应该起作用:

    using(var db = new ARContext())
    {
      var groupNames = new[] {"CRM_ADMIN","CRM_Boutique1","CRM_Boutique2"};
    
      //Fetch application (AdGroups eager loaded) if it exists, otherwise create a new one
      var application = db.Applications.Include(a => a.AdGroups)
                                       .FirstOrDefault(a => a.Application == "CRM") 
                                       ?? db.Add(new Application { Application = "CRM" });
    
      //If the application didn't exist yet, initialize the AdGroup collection
      //Better to do this in the constructor of your application model though
      if(db.Entry(application).State == EntityState.Added)
         application.AdGroups = new List<AdGroup>();
    
      //Iterate over groupNames that are not part of application.Adgroup's collection           
      foreach(var name in groupNames.Where(g => !application.AdGroups.Any(ag => ag.GroupName == g)))
      {
          AdGroup group = db.AdGroups.FirstOrDefault(ag => ag.GroupName == name) 
                          ?? db.Add(new AdGroup { GroupName = name });
          application.AdGroups.Add(group);
      }
    
      db.SaveChanges();     
    }
    
    使用(var db=new ARContext())
    {
    var groupNames=new[]{“CRM_管理”、“CRM_精品店1”、“CRM_精品店2”};
    //获取应用程序(已加载),如果它存在,则创建一个新的应用程序
    var application=db.Applications.Include(a=>a.AdGroups)
    .FirstOrDefault(a=>a.Application==“CRM”)
    ??db.Add(新应用程序{Application=“CRM”});
    //如果应用程序尚不存在,请初始化AdGroup集合
    //不过,最好在应用程序模型的构造函数中这样做
    if(db.Entry(application.State==EntityState.Added)
    application.AdGroups=新列表();
    //迭代不属于application.Adgroup集合的组名
    foreach(groupNames.Where(g=>!application.AdGroups.Any(ag=>ag.GroupName==g))中的变量名)
    {
    AdGroup group=db.AdGroups.FirstOrDefault(ag=>ag.GroupName==name)
    ??db.Add(新的AdGroup{GroupName=name});
    application.AdGroups.Add(组);
    }
    db.SaveChanges();
    }
    

    您的示例有点不寻常,因为您对
    应用程序
    AdGroup
    或它们之间的关系一无所知,这会导致代码中出现大量检查。首先,如果应用程序存在(包括
    AdGroups
    Eager load
    ),我将从数据库中获取该应用程序,否则我将创建一个新的应用程序。如果我必须创建一个新集合,则应该初始化
    AdGroup
    集合(除非您在模型的构造函数中这样做)。最后,迭代不在集合
    应用程序.AdGroups
    中的组名。如果该组存在,则获取该组,如果不存在,则创建该组并将其添加到
    Application.AdGroups

    你能展示你的地图吗?如果映射正确,EF不应该插入重复项,所以不需要检查记录是否存在或存在anything@Alexander:我不是说它在插入重复项。我是说它不必要地抱怨重复插入。我对各个列都有唯一的限制。你不是使用fluent api
    .Map
    方法吗?你确定你有正确的左右键吗?@wickd如果你想添加一个应用程序,你必须从数据库中获取与之对应的adgroup(或者先在数据库中创建它们),将它们分配给应用程序,然后只添加应用程序。不知道任何事情的原因是,我假设一个无状态的pov。因此,如果1个客户端删除了
    var val = new Applications
    {
        Application = "CRM",
        Groups = new List<AdGroup> {
            new AdGroup { Group = "CRM_ADMIN" },
            new AdGroup { Group = "CRM_Boutique1" },
            new AdGroup { Group = "CRM_Boutique2" },
        }
    };
    
    var dbArr = db.Applications.Where(a => a.Application == val.Application).FirstOrDefault();
    
    if (dbArr == null)
    {
        db.Applications.Add(new Applications() { Application = val.Application });
        db.SaveChanges();
    }
    
    dbArr = db.Applications.Where(a => a.Application == val.Application).FirstOrDefault();
    
    if (dbArr.Groups == null)
    {
        dbArr.Groups = new List<AdGroup>();
    }
    
    foreach (var gr in val.Groups)
    {
        var dbGrp = db.Groups.Where(g => g.Group == gr.Group).FirstOrDefault();
    
        if (dbGrp == null)
        {
            dbArr.Groups.Add(gr);
        }
        else
        {
            dbArr.Groups.Add(dbGrp);
        }
    }
    
    db.SaveChanges();
    
    using(var db = new ARContext())
    {
      var groupNames = new[] {"CRM_ADMIN","CRM_Boutique1","CRM_Boutique2"};
    
      //Fetch application (AdGroups eager loaded) if it exists, otherwise create a new one
      var application = db.Applications.Include(a => a.AdGroups)
                                       .FirstOrDefault(a => a.Application == "CRM") 
                                       ?? db.Add(new Application { Application = "CRM" });
    
      //If the application didn't exist yet, initialize the AdGroup collection
      //Better to do this in the constructor of your application model though
      if(db.Entry(application).State == EntityState.Added)
         application.AdGroups = new List<AdGroup>();
    
      //Iterate over groupNames that are not part of application.Adgroup's collection           
      foreach(var name in groupNames.Where(g => !application.AdGroups.Any(ag => ag.GroupName == g)))
      {
          AdGroup group = db.AdGroups.FirstOrDefault(ag => ag.GroupName == name) 
                          ?? db.Add(new AdGroup { GroupName = name });
          application.AdGroups.Add(group);
      }
    
      db.SaveChanges();     
    }