In Entity Framework you can work with foreign key associations. That is, a foreign key to another object is expressed as a pair of two properties: a primitive foreign key property (e.g. NominalRouting.OrderItemId
) and an object reference (NominalRouting.OrderItem
).
This means that you can either set a primitive value or an object reference to establish a foreign key association. If you set one of them, EF tries to keep the other one in sync, if possible. Unfortunately, this may also give rise to conflicts between primitive foreign key values and their accompanying references.
It's hard to tell what exactly happens in your case. However, I do know that your approach of "copying" objects from one parent to another is... not ideal. First, it's never a good idea to change primary key values. By setting them to 0
you make the object look like new, but they aren't. Secondly, you assign the same child objects to other parent objects many times. I think that, as a consequence, you end up with a large number of objects having a foreign key value but not a reference.
I said "copying", because that's what you seemingly try to achieve. If so, you should properly clone objects and Add
them to each targetOrderItem
. At the same time, I wonder why you (apparently) clone all these objects. It looks like many-to-many associations are more appropriate here. But that's a different subject.
Now your actual question: how to find the conflicting associations?
That's very, very hard. It would require code to search through the conceptual model and find properties involved in foreign key associations. Then you'd have to find their values and find mismatches. Hard enough, but trivial when compared to determining when a possible conflict is an actual conflict. Let me clarify this by two examples. Here, a class OrderItem
has a required foreign key association consisting of properties Order
and OrderId
.
var item = new OrderItem { OrderId = 1, ... };
db.OrderItems.Add(item);
db.SaveChanges();
So there's an item with OrderId
assigned and Order
= null, and EF is happy.
var item = db.OrderItems.Include(x => x.Order).Find(10);
// returns an OrderItem with OrderId = 1
item.Order = null;
db.SaveChanges();
Again, an item with OrderId
assigned and Order
= null, but EF throws the exception "The relationship could not be changed...".
(and there are more possible conflict situations)
So it's no enough to look for unmatched values in OrderId/Order
pairs, you'd also have to inspect entity states and know exactly in which combination of states a mismatch is not allowed. My advice: forget it, fix your code.
There's one dirty trick though. When EF tries to match foreign key values and references, somewhere deep down in a tree of nested if
s it collects the conflicts we're talking about into a member variable of the ObjectStateManager
, named _entriesWithConceptualNulls
. It's possible to get its value by doing some reflection:
#if DEBUG
db.ChangeTracker.DetectChanges(); // Force EF to match associations.
var objectContext = ((IObjectContextAdapter)db).ObjectContext;
var objectStateManager = objectContext.ObjectStateManager;
var fieldInfo = objectStateManager.GetType().GetField("_entriesWithConceptualNulls", BindingFlags.Instance | BindingFlags.NonPublic);
var conceptualNulls = fieldInfo.GetValue(objectStateManager);
#endif
conceptualNulls
is a HashSet<EntityEntry>
, EntityEntry
is an internal class, so you can only inspect the collection in the debugger to get an idea of conflicting entities. For diagnostic purposes only!!!