C# 插入实体框架子项的顺序
我有一个这样的结构C# 插入实体框架子项的顺序,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,我有一个这样的结构 public class Son { public string Name {get;set;} public int Age {get;set;} } public class Daughter { public string Name {get;set;} public int Age {get;set;} } public class Parent { public Daughter[] Daughters {get;set;}
public class Son {
public string Name {get;set;}
public int Age {get;set;}
}
public class Daughter {
public string Name {get;set;}
public int Age {get;set;}
}
public class Parent {
public Daughter[] Daughters {get;set;}
public Son[] Sons {get;set;}
}
其中有一个FK父->子和父->子
当前,在父对象上执行上下文.SaveChanges()
时,它会保存父对象,然后保存子对象,然后保存子对象。我需要它先保存子对象,再保存子对象,因为我们有一个数据库触发器,它根据子对象对子对象进行验证(如果不满足要求,则会拒绝整个过程)
这一触发显然超出了EF的知识范围
我如何指定儿子在EF中依赖于女儿,以便儿子首先插入;或者是否有可以定义插入顺序的规范或属性
附言:不要过多地研究人为的例子(比如为什么我们不把它保存在一个叫做儿童的东西下)。现实世界中的例子要复杂得多,但先救儿子后救女儿的想法已经存在了我喜欢挑战
首先声明:我不喜欢触发器,也不喜欢为使插入顺序变得重要而建立需求。我的第一项工作是用尽一切办法来取消这一要求
至少在添加实体时,我可以看到,在进行了一些修补之后,例如,一个父实体有一个或多个子实体和一个或多个子实体,插入顺序始终是基于实体名称的字母顺序。例如,对于名为“父”、“子”和“子”的实体,插入始终为父>子>子。属性、配置、插入、甚至表名的顺序对操作没有影响,但是将实体类“Son”重命名为“ASon”会导致在子类之前插入子类。我不知道这是否会继续进行编辑,但这是一个值得考虑的问题,而不是过于陈旧。(尽管这样的东西肯定需要在系统中记录好,以防有人质疑命名约定,从而在其他东西之前插入一些东西。)
也就是说,进入一个有趣的行业
使用名为ASon的子实体强制子实体在子实体之前插入子实体,可以让EF反转插入顺序:
using (var context = new ParentDbContext())
{
var parent = context.Parents.Create();
parent.Name = "Steve";
parent.Daughters.Add(new Daughter { Name = "Elise" });
parent.Daughters.Add(new Daughter { Name = "Susan" });
parent.Sons.Add(new ASon { Name = "Jason" });
parent.Sons.Add(new ASon { Name = "Duke" });
context.Parents.Add(parent);
context.SaveChanges();
}
开箱即用,插入父母、儿子、儿子、女儿、女儿
为了扭转这种局面,我否决了SaveChanges,希望我们的儿子们将储蓄推迟到其他事情之后:
public override int SaveChanges()
{
var trackedStates = new[] { EntityState.Added, EntityState.Modified };
var trackedParentIds = ChangeTracker.Entries<Parent>().Where(x => trackedStates.Contains(x.State)).Select(x => x.Entity.ParentId).ToList();
var addedSons = ChangeTracker.Entries<ASon>().Where(x => x.State == EntityState.Added).ToList();
var modifiedSons = ChangeTracker.Entries<ASon>().Where(x => x.State == EntityState.Modified).ToList();
int tempid = -1;
int modifiedParentCount = addedSons.Select(x => x.Entity.Parent.ParentId)
.Where(x => trackedParentIds.Contains(x))
.Count();
List<Tuple<Parent, ASon>> associatedSons = new List<Tuple<Parent, ASon>>();
modifiedSons.ForEach(x => { x.State = EntityState.Unchanged; });
addedSons.ForEach(x =>
{
x.Entity.SonId = tempid--;
associatedSons.Add(new Tuple<Parent, ASon>(x.Entity.Parent, x.Entity));
x.Entity.Parent.Sons.Remove(x.Entity);
x.State = EntityState.Unchanged;
});
var result = base.SaveChanges();
addedSons.ForEach(x => { x.Entity.Parent = associatedSons.Single(a => a.Item2 == x.Entity).Item1; x.State = EntityState.Added; });
modifiedSons.ForEach(x => { x.State = EntityState.Modified; });
result += base.SaveChanges() - modifiedParentCount;
return result;
}
public override int SaveChanges()
{
var trackedStates=new[]{EntityState.Added,EntityState.Modified};
var trackedParentIds=ChangeTracker.Entries()。其中(x=>trackedStates.Contains(x.State))。选择(x=>x.Entity.ParentId.ToList();
var addedSons=ChangeTracker.Entries()。其中(x=>x.State==EntityState.Added.ToList();
var modifiedSons=ChangeTracker.Entries();
int tempid=-1;
int modifiedParentCount=adddsons.Select(x=>x.Entity.Parent.ParentId)
.Where(x=>trackedParentIds.Contains(x))
.Count();
List associatedSons=新列表();
modifiedSons.ForEach(x=>{x.State=EntityState.Unchanged;});
addedSons.ForEach(x=>
{
x、 Entity.SonId=tempid--;
Add(新元组(x.Entity.Parent,x.Entity));
x、 实体。父项。子项。删除(x.Entity);
x、 状态=实体状态。未更改;
});
var result=base.SaveChanges();
addedSons.ForEach(x=>{x.Entity.Parent=associatedSons.Single(a=>a.Item2==x.Entity).Item1;x.State=EntityState.Added;});
modifiedSons.ForEach(x=>{x.State=EntityState.Modified;});
结果+=base.SaveChanges()-modifiedParentCount;
返回结果;
}
那么这是在做什么:
第一点很简单,我们找到了添加和修改的子元素。我们还统计了修改和添加儿子的父母数量。完成此操作后,这些将被重复计算
对于修改后的子对象,我们只是将其状态设置为未更改。
为了增加儿子,我们需要做一些肮脏的工作。我们需要给他们一个临时的唯一ID,因为要将他们标记为未更改,EF仍然希望跟踪他们的ID,并且当您添加两个儿子时,它将在这里失败。请注意,当我们将它们放回添加的位置时,它们将从标识列接收正确的ID,而不是这些临时的负ID。我们还跟踪它们添加的子元素与它们各自的父元素在元组中的关联,因为我们需要临时将这些子元素从它们的父元素中删除。最后,添加的子也标记为未更改。
现在,我们称之为基础SaveChanges,它将拯救我们的父母和他们的女儿。
对于修改后的子系统,我们只需要将状态更新回modified。
对于添加的子对象,我们使用保存的关联将其重新分配给其父对象,然后将其状态设置回“已添加”。
我们再次调用基本SaveChanges,将受影响的行数附加到第一次运行,并减去重复的父引用。(由于被修改而已计数的父项)
粗略的一点是调整双重保存的结果计数,这可能不是100%准确,但只有在使用SaveChanges的结果时才应该是一个问题。我不能说我曾经真正关注过这个返回值:)
希望这能给你一些想法。也许可以给你的“儿子”类添加[必需]
属性的公共女儿所有者Daughter
?