C# 实体框架插入父子孙对象
我正在尝试插入一个包含n个子项的父实体,该子实体可以进一步包含n个自己的子项。当我插入一个没有子对象的对象时,一切正常,但一旦输入对象包含子对象,就会在Context.SaveChanges()上显示以下错误: “操作失败:无法更改关系,因为一个或多个外键属性不可为null。对关系进行更改时,相关外键属性设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。” 家长:C# 实体框架插入父子孙对象,c#,entity-framework,C#,Entity Framework,我正在尝试插入一个包含n个子项的父实体,该子实体可以进一步包含n个自己的子项。当我插入一个没有子对象的对象时,一切正常,但一旦输入对象包含子对象,就会在Context.SaveChanges()上显示以下错误: “操作失败:无法更改关系,因为一个或多个外键属性不可为null。对关系进行更改时,相关外键属性设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。” 家长: public class Parent : Entity {
public class Parent : Entity
{
public Parent()
{
this.Children = new HashSet<Children>();
}
public virtual ICollection<Child> Children { get; set; }
}
以下是我的DBContext:
modelBuilder.Entity<Child>().ToTable("Children")
.HasRequired<Parent>(x => x.Parent);
modelBuilder.Entity<GrandChild>().ToTable("GrandChildren")
.HasRequired<Child>(y => y.Child);
modelBuilder.Entity<Parent>().ToTable("Parents")
.HasMany(z => z.Child)
.WithRequired(i => i.Parent);
插入似乎没有问题。似乎我一直在错误的地方寻找问题。的确,我知道这将是一个固定的最大3深度,所以我采用了这种设计,但我会记住你所说的。在主题上,我通过将diffParent映射到DTO,然后进行拾取和后续操作,解决了这个问题将其映射回我传递给insert方法的实体列表。您可能为该问题编写了此代码,这是可以的,但在这种情况下不太可能发生异常。是否在实际代码中,您重新分配了现有(grand)值其他父母的子女?谢谢你的评论,你说得对。代码确实是用于演示的。至于现有部分:我将所有的子女和孙子作为新对象生成,我唯一接触现有实体的时间是在我迭代输入实体列表时。你能修改代码使其更接近真实的实体吗代码。感兴趣的部分是输入实体是否附加到上下文,以及在设置子属性时是否设置了任何引用属性。我引用输入列表中每个实体的Id,并将其添加为每个子项的属性。我将其添加到代码列表中。其他属性只是硬编码值或作为输入属性输入的值,并且这些值都没有链接到任何实体。
parent.Child.Add(Child);
应该是parent.Children.Add(Child);
?另外,如果已经在循环中执行了,为什么要在循环后执行此操作?Child.granner.Add(granner)
alkso看起来应该是child.grandrenes.Add(grandren);
在我们开始查找错误代码之前,您能仔细检查您的代码并确保它反映您的实际代码吗?
public class GrandChild : Entity
{
public int ChildId { get; set; }
public virtual Child Child { get; set; }
}
modelBuilder.Entity<Child>().ToTable("Children")
.HasRequired<Parent>(x => x.Parent);
modelBuilder.Entity<GrandChild>().ToTable("GrandChildren")
.HasRequired<Child>(y => y.Child);
modelBuilder.Entity<Parent>().ToTable("Parents")
.HasMany(z => z.Child)
.WithRequired(i => i.Parent);
public Parent Insert(List<AnotherObject> input)
{
Parent parent = new Parent();
// Set parent attributes
foreach (var x in input)
{
Child child = new Child();
// Set child attributes
// EDIT: I also set an attribute based on the list of
// entities from the input
child.OtherObjectId = x.Id;
child.Parent = parent;
if (x.Children.Count > 0)
{
foreach (var y in x.Children)
{
GrandChild grandChild = new GrandChild();
// Set grandChild attributes
grandChild.Child = child;
child.GrandChildren.Add(grandChild);
}
}
parent.Children.Add(child);
}
Context.Parents.Add(parent);
Context.SaveChanges();
}
Random rand = new Random(DateTime.Now.ToString().GetHashCode());
var selected = diffParent.DiffChild.OrderBy(x => rand.Next()).Take(diffParent.AmountShown).ToList();
foreach (var q in selected)
{
var listOne = new List<DiffChild>();
var listTwo = new List<DiffChild>();
if (q.CountAttribute != null)
listOne = q.DiffChild.Where(c => c.Attribute == true).OrderBy(x => rand.Next()).Take((int)q.CountAttribute).ToList();
if (q.OtherCountAttribute != null)
listTwo = q.DiffChild.Where(d => d.Attribute != true).OrderBy(y => rand.Next()).Take((int)q.OtherCountAttribute).ToList();
q.DiffChildren = listOne.Concat(listTwo).ToList();
}
var selected = diffParent.DiffChild.OrderBy(x => rand.Next()).Take(diffParent.AmountShown).ToList();