Ef 6.0多对多插入如此多的编码..为什么?
本文关键字:编码 为什么 插入 Ef | 更新日期: 2023-09-27 18:27:39
我的问题更多的是为什么ef 6.0不支持忽略重复项?
让我们举一个例子:
我有两张桌子
- 应用程序{id,AppName}
- AdGroup{id,GroupName}
应用程序与ADGroups之间存在多对多关系。现在,每次我添加带有广告组的应用程序时,我都需要首先执行以下操作以避免重复的密钥插入:
- 检查应用程序是否已存在
- 检查指定的ADGroups是否已存在
- 找出差异
- 更新数据库
这似乎只是为了插入一段血腥的关系而做的大量工作。可以编写一个sql查询来在插入中进行选择,以确保数据不在那里,然后执行插入。它将返回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
)
因此,基本上,即使应用程序、广告组或关系已经存在,它也不会插入任何内容。。。
一天结束时,将对数据库进行一个简单的调用。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");
});
编辑下面是我用来插入关系的代码示例:
使用(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();
}
上面使用的名称和代码示例有一些差异,但要点就在那里。。。
因此,首先我需要保存新的应用程序,然后处理各个组,看看它们是否存在,并相应地添加到上下文中。这是除了编写存储过程之外的唯一方法吗??
感谢
类似的东西也应该起作用:
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
中。