0

I am inserting or updating a parent entity with associated children entities. Entity framework inserts or updates the entities BUT it never creates or updates the links between them even though they exist in C#.

public void MergeParent(Parent parent)
{
    // Set Parent
    var parentInDB = context.Parents.SingleOrDefault(p => p.ParentID == parent.ParentID);

    if (parentInDB != null)
    {
        parent.ID = parentInDB.ID;
        context.Entry(parentInDB).CurrentValues.SetValues(parent);
    }
    else
    {
        context.parents.Add(parent);
    }

    // Set child
    foreach(var child in parent.children)
    {
        var childInDB = context.children.SingleOrDefault(a => a.DiscogsID == child.DiscogsID && child.DiscogsID != null);

        if (childInDB != null)
        {
            child.ID = childInDB.ID;
            context.Entry(childInDB).CurrentValues.SetValues(child);
        }
        else
        {
            context.children.Add(child);
        }
    }

    // Finally Save
    context.SaveChanges();
}

If I set a breakpoint, I can see the parent has the children associated, but while the database contains the elements it does not ever update the link table.

jjj
  • 4,822
  • 1
  • 16
  • 39
Three Value Logic
  • 1,102
  • 1
  • 15
  • 37
  • Painful, but this is how it can be done. http://stackoverflow.com/questions/5538974/the-relationship-could-not-be-changed-because-one-or-more-of-the-foreign-key-pro/5540956#5540956 – Steve Greene May 28 '15 at 19:49

1 Answers1

1
   // Set child
   foreach(var child in parent.children)
   {
       var childInDB = context.children.SingleOrDefault(a => a.DiscogsID == child.DiscogsID && child.DiscogsID != null);

       if (childInDB != null)
       {
           child.ID = childInDB.ID;
           context.Entry(childInDB).CurrentValues.SetValues(child);
       }
       else
       {
           context.children.Add(child);
       }
   }

The problem is in the section above, for the children, you're adding to and retrieving from the database instead of from the parentInDb's collection of children. I don't think SetValues updates relationships.

I modified some of your code and added some comments:

// Add an include to bring in the children
var parentInDB = context.Parents.Include(p => p.children)
    .SingleOrDefault(p => p.ParentID == parent.ParentID);

if (parentInDB != null)
{
    // This line shouldn't be necessary...
    // parent.ID = parentInDB.ID;
    context.Entry(parentInDB).CurrentValues.SetValues(parent);

    // Set child
    foreach(var child in parent.children)
    {
        // Should search in parentInDB, not context 
        // If DiscogsID is a primary key, it can't be null
        var childInDB = parentInDB.children.SingleOrDefault(a => a.DiscogsID == child.DiscogsID);

        if (childInDB != null)
        {
            // This line shouldn't be necessary...
            // child.ID = childInDB.ID;
            context.Entry(childInDB).CurrentValues.SetValues(child);
        }
        else
        {
            // Should add to parentInDB, not context
            parentInDB.children.Add(child);
        }            
    }
    // Would children in parentInDB.children not found in parent.children need to be removed?
}
else
{
    // This will automatically add untracked children
    context.parents.Add(parent);
}

// Finally Save
context.SaveChanges();

I don't know what happens if you add a new parent with previously attached entities in children.

jjj
  • 4,822
  • 1
  • 16
  • 39
  • @Steve Greene's link in his comment shows a more complete example with children that need to be removed – jjj May 28 '15 at 21:01
  • There might be a better way of doing it but setting the ID to the InDB ID stops EF from updating an existing record with a null ID. – Three Value Logic May 30 '15 at 09:40