I'm trying to insert a parent entity with n children that can further have n of their own children. When I insert an object that has no grandchildren everything works fine, but as soon as the input object contains grandchildren the following error is presented on Context.SaveChanges():
"The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted."
Parent:
public class Parent : Entity
{
public Parent()
{
this.Children = new HashSet<Children>();
}
public virtual ICollection<Child> Children { get; set; }
}
Child:
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; }
}
Grandchild:
public class GrandChild : Entity
{
public int ChildId { get; set; }
public virtual Child Child { get; set; }
}
Here's my 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);
Then finally my insert is as follows, I build a new parent-child-grandchild object conditionally based on another input object (I'm trying to save the initial state of a questionnaire based on a similar parent-child-grandchild questionnaire object hierarchy):
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();
}
I've checked the DB and entities several times so I'm hoping there's some kind of flaw in my insert logic instead.
EDIT: This is where the input list (selected) comes from in case that helps to determine something:
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();
}
EDIT: The issue seems to stem from the selected list and to be more specific from the for loop where I try to select specific entities from the full list, if I pass only this:
var selected = diffParent.DiffChild.OrderBy(x => rand.Next()).Take(diffParent.AmountShown).ToList();
The insert seems to work without issues. Seems I've been hunting for issues in the wrong place.
parent.Child.Add(child);Should that beparent.Children.Add(child);? Also, why do you do that after the loop, if you did it inside the loop already?child.GrandChild.Add(grandChild);alkso looks like it should bechild.GrandChildren.Add(grandChild);Could you double check your code, and make sure it reflects your actual code, before we start hunting errors in the wrong code? - oerkelens