Apparently, EF6 doesn't like objects that have multiple foreign key properties that use the same key value, but do not share the same reference. For example:
var user1 = new AppUser { Id = 1 };
var user2 = new AppUser { Id = 1 };
var address = new Address
{
CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference
};
When I attempt to insert this record, EF throws this exception:
Saving or accepting changes failed because more than one entity of type
'AppUser' have the same primary key value. [blah blah blah]
I've discovered that doing this resolves the issue:
var user1 = new AppUser { Id = 1 };
var user2 = user1; //same reference
I could write some helper code to normalize the references, but I'd rather EF just know they're the same object based on the ID alone.
As for why EF does this, one explanation could be that its trying to avoid doing multipe CRUD operations on the same object since separate instances of the same entity could contain different data. I'd like to be able to tell EF not to worry about that.
Update
So it's as I suspected per my last paragraph above. In absense of a means to tell EF not to do CRUD on either instance, I will just do this for now:
if (address.ModifiedBy.Id == address.CreatedBy.Id)
{
address.ModifiedBy = address.CreatedBy;
}
Works well enough so long as I am not trying to do CRUD on either.
Update2
I've previously resorted to doing this to prevent EF from validating otherwise-required null properties when all I need is the child entity's ID. However, it doesn't keep EF from going into a tizzy over separate instances with the same ID. If it's not going to do CRUD on either AppUser
object, why does it care if the instances are different?
foreach (var o in new object[] { address.ModifiedBy, address.CreatedBy })
{
db.Entry(o).State = EntityState.Unchanged;
}
If you get
AppUser
from context, then you will not need to do anything, because Entity Framework will track entities:Now, they both will point to same objects and will not cause to conflict.
You can add two extra properties to have the Id for the main objects which is the
AppUser
, then you can use only oneAppUser
object and reference it for both the created and modified by properties.Otherwise, your code will end up by saving two instances of
AppUser
with the same primary key.Another approach is to set both the foreign key properties to only one
AppUser
objectThe explanation is that EF's change tracker is an identity map. I.e. a record in the database is mapped to one, and only one, CLR object.
This can be demonstrated easily by trying to attach two objects with the same key:
The second line will throw an exception:
This also happens if you assign
Somewhere in the process,
user1
anduser2
must be attached to the context, giving rise to the exception you get.Apparently, you have a function that receives two
Id
values that can be different or identical. Admittedly, it would be very convenient if you could simply create twoAppUser
instances from theseId
s, not having to worry about identical keys. Unfortunately, your solution ...... is necessary. Solid enough, though.