实体框架插入父子孙子对象

时间:2016-06-13 07:48:29

标签: c# entity-framework

我试图插入一个有n个孩子的父实体,这些孩子可以进一步拥有自己的孩子。当我插入一个没有孙子的对象时,一切正常,但只要输入对象包含孙子,就会在Context.SaveChanges()上显示以下错误:

"操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。"

父:

 public class Parent : Entity
    { 
        public Parent()
        {
            this.Children = new HashSet<Children>();
        }        
        public virtual ICollection<Child> Children { get; set; }
    }

子:

 public class Child : Entity
    {
        public Child ()
        {
            this.GrandChildren = new HashSet<GrandChild>();
        }
        public virtual ICollection<GrandChild> GrandChildren { get; set; }      
        public int ParentId { get; set; }
        public virtual Parent Parent { get; set; }
    }

孙:

 public class GrandChild : Entity
    {
        public int ChildId { get; set; }       
        public virtual Child Child { 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); 

然后最后我的插入如下,我根据另一个输入对象有条件地建立一个新的父子孙对象(我试图根据类似的亲子 - 保存问卷的初始状态 - 孙子问卷对象层次结构):

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();
        }

编辑:问题似乎源于所选列表,并且更具体来自for循环,我尝试从完整列表中选择特定实体,如果我只传递这个:

var selected = diffParent.DiffChild.OrderBy(x => rand.Next()).Take(diffParent.AmountShown).ToList();

插入似乎没有问题。似乎我一直在寻找错误地方的问题。

1 个答案:

答案 0 :(得分:0)

确实如此,我知道这将是一个固定的最大深度3,所以我采用了这种设计,但我会记住你的想法。关于主题我设法通过将diffParent映射到DTO,然后执行拾取并将其映射回我传递给insert方法的实体列表来解决此问题。

相关问题