我的问题更多的是为什么ef 6.0不支持忽略重复?
我有两张桌子
应用程序与ADGroups有很多对。现在,每次我添加一个包含广告组的应用程序时,我都需要先执行以下操作以避免重复的密钥插入:
这似乎只是为了插入血腥的关系而做了很多工作。可以编写sql查询来执行insert中的select以确保数据不在那里然后执行插入。如果行已经存在,它将返回0或1
假设n到n表将被称为Applications_AdGroup
然后插入关系的查询将是这样的(未经测试):
Insert Into Applications (AppName)
select 'CRM'
where NOT EXISTS(
select 1
from Applications
where AppName = 'CRM'
)
Insert Into AdGroup (GroupName)
select 'CRM_ADMIN'
where NOT EXISTS(
select 1
from Applications
where AppName = 'CRM_ADMIN'
)
Insert Into Applications_AdGroup (id_adgroup, id_applications)
select
adgroup.id,
applications.id
from
adgroup,
applications
where
adgroup.GroupName = 'CRM_ADMIN' AND
applications.AppName = 'CRM' AND
WHERE NOT EXISTS (
select 1
from
Applications_Adgroup
where
Applications_AdGroup.id_adgroup = adgroup.id AND
Applications_AdGroup.id_applications = applications.id
)
所以基本上即使应用程序,广告组或关系已经存在,它也不会插入任何内容......
一天结束时,将对db.Applications.Add(obj)进行简单调用,然后保存更改。所有检查都在后台进行,一切都很顺利?
对此有何看法?我只是做错了吗?
修改的 我想可能会出现一些并发问题。在上述4个步骤中的任何一个步骤中,另一个进程可能会插入广告组,无论如何您都会遇到重复的密钥错误
修改的 这里有映射:
//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");
});
修改的 这是我用来插入关系的代码示例:
使用(var db = new ARContext()) {
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();
}
上面使用的名称和代码示例存在一些差异,但要点就是......
首先,我需要保存新的应用程序,然后通过各个组来查看它们是否存在并相应地添加到上下文中。除了编写存储过程之外,这是除此之外的唯一方法吗?
由于
答案 0 :(得分:1)
这样的事情也应该做到这一点:
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();
}
您的示例有点不寻常,因为您对Application
,AdGroup
或它们之间的关系一无所知,这会导致代码中的大量检查。首先,我从数据库中获取应用程序(如果它存在(包括AdGroups
到Eager Loading
),否则我创建一个新的应用程序。如果我必须创建一个新集合,则应初始化AdGroup
集合(除非您在模型的构造函数中执行此操作)。最后,迭代集合Application.AdGroups
中不包含的组名。如果该组存在,则获取它,如果它不存在,则创建它并将其添加到Application.AdGroups
。