2016-06-13 76 views
2

我試圖插入一個有n個子項的父項實體,這個子項可以進一步包含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(); 

插入似乎沒有問題需要解決。似乎我一直在錯誤的地方尋找問題。

+0

您可能爲該問題製作了這個代碼,這是可以的,但這種情況不太可能發生異常。難道在你的真實代碼中,你是否將現有的(大)孩子重新分配給其他父母? –

+0

感謝您的評論,你是對的代碼確實是介紹。至於現有部分:我將所有子孫作爲新對象生成,並且只有當我遍歷輸入實體列表時,纔會觸及現有實體。 –

+0

您可以修改您的代碼,使其更接近真實的代碼。感興趣的部分是輸入實體是否附加到上下文,以及設置子屬性時是否設置了任何引用屬性。 –

回答

0

的確,我知道這將是一個固定的最大3深度,所以我採用這種設計,但我會保留你在前面說的內容。在主題上,我設法通過將diffParent映射到DTO來解決此問題,然後執行拾取並將其映射回到我傳遞給插入方法的實體列表中。