I want to set a foreign key on an entity. I have the foreign entity exposed in my user control, and want to set it via WinForms data binding.
Here's the catch - the foreign entity was originally loaded from another repository/DbContext, as the user control populates itself independently using its own repository.
Unfortunately this doesn't work "out of the box", as this example demonstrates:
var repository1 = GetRepository();
var categoryFromRepository1 = repository1.GetAll<Category>().First();
var repository2 = GetRepository();
var appointmentFromRepository2 = repository2.GetNewAppointment();
appointmentFromRepository2 .Category = categoryFromRepository1;
repository2.Add(appointmentFromRepository2);
repository2.SaveChanges();
This fails on at Add() with the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
OK, so repository2 can't auto-attach the Category because it's attached to repository1. Great, so let's detach first:
repository1.Detach(categoryFromRepository1);
Which fails on SaveChanges() due to a validation error - whoops, turns out repository2 thinks it's an Added entry and trying to insert. Great, so let's attach as well to avoid this:
repository2.Attach(categoryFromRepository1);
And this works! Problem solved. I've now set the repository2-entity property to the repository1-entity, voila.
Except that this solution sucks swamp water... We have many data-bound self-populating user controls throughout the program, and manually detaching/reattaching all the foreign entity references prior to SaveChanges() is a horrible solution. Furthermore, supposing the repository we're saving via happens to have the object attached already then we get this error when we Attach():
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
None of the solutions I can think of are that great:
1) In our generic repository class on SaveChanges(), scan all foreign references on all modified entities for out-of-DbContext entity references, dynamically change them to the in-DbContext entity reference (load from DB if necessary)
2) Don't set the navigation property at all, just set the foreign key ID field (sucks0rz yo' b0x0rz)
3) Manually do these checks before save (violates DRY & persistence-ignorance principles)
4) Abandon data-binding to these properties, manually set properties & load entities from the main repository (terrible - means extra queries to the database for data we already have)
5) Fudge user controls so that they can load their data from a given repository, if required (poor solution, violates some basic design principle... but workable)
Any other ideas, plz?
Regards,
-Brendan