I don't know this "Painting the state" method, but I'm not surprised that your example doesn't work.
With context.Set<TEntity>().Add(root)
three things happen:
- The root (=
employee
) is inAdded
state - All children (=
employee.PlacesOfEmployment
) are inAdded
state - All relationship entries between root and children are in
Added
state
When you iterate over context.ChangeTracker.Entries
you only fetch the entities from the context, but not the relationship entries (which are separate artifacts stored inside the context). In this loop you reset the state of root and children to Modified
or Unchanged
respectively. But this is only a change of that entity state. The relationship states are still Added
and those states get translated into an INSERT
into the "relationship table". That's why you get the duplicate key exception because the records to link root and children are already there.
Although the underlying ObjectContext
allows to access relationship entries besides the entity state entries as well I doubt it will help because how could the ApplyChangesInGraph
method recognize that the graph that is passed into the method has added or deleted or unchanged relationships if you only have one State
property per entity?
Now, you could probably make your test method work if you use context.Set<TEntity>().Attach(root);
instead of ...Add(root)...
because this would put all entities and relationships into Unchanged
state (or - I believe - it won't store any relationship entries in the context at all). As a result no INSERT into the link table (nor a DELETE from that table) should happen. However, I'm afraid, that with ...Attach
the ApplyChangesInGraph
method won't work then correctly anymore if you have an object graph with really new (or deleted) relationships where you actually expect an INSERT (or DELETE) for the link table.
Honestly, I have no clue how you could implement that generic method so that it works generally for all possible change scenarios. It seems to me that the object graph (with one State
property per entity) just doesn't contain enough information to describe all relationship changes that could have happened while the graph was disconnected. (It would interest me how Julie Lerman and Rowan Miller are proposing to implement it.)