Reputation: 1579
When I try to add new child relations to an existing parent object, entity tries to insert the parent object as new, instead of updating it as modified. I get an error saying its trying to insert a duplicate key.
This is really stumping me, it wasn't behaving like this until I updated the model with a new relation (via update from database, not code first). Other tables in the same context, with the same many-to-many pattern do not cause this error!
I've found that if I add my child object to the context, carefully setting the ID values, not the navigation properties, it will save fine. But the fix-up process isn't adding the child object to the navigation collection, wich cause logic issues in other places.
My model has a many to many relation like this:
option -< optionUnit >- Unit
Both Option and Unit objects are existing and loaded into the context.
Normally I would make the bridge table and set the navigation properties like below:
bridge = new OptionUnit()
{
OptionUnitId = Guid.NewGuid(),
Unit = SelectedUnit,
Option = SelectedOption,
};
//Context.OptionUnits.Add(bridge); //added to context via the navigation properties
But when I do this time, entity tried to insert SelectedOption as new (even though its entity state is modifed at time of the save, not new or detached).
To get around this I've had to make the bridge and set the id's only. I get no error on save, but its not automatically added to SelectedOption.OptionUnits via fix-up like I would expect. If i add it to the collection manually, I get the save error again.
bridge = new OptionUnit()
{
OptionUnitId = Guid.NewGuid(),
//Unit = SelectedUnit,
UnitId = SelectedUnit.UnitId,
//Option = SelectedOption,
OptionId = SelectedOption.OptionId,
};
Context.OptionUnits.Add(bridge);
This seems to be only happening for relations on the Options Entity. The other relation, between optionUnit >- Unit has no problems and works as expected.
It seems like theres somethign wrong with the relations, but I'm not sure where to look. I need to know whats causing this behaviour, how to fix it, and how to prevent it from happening in the future....
Upvotes: 1
Views: 3682
Reputation: 1579
I found the issue. After adding a child item, I would run some logic to update some totals. The problem was I used RaiseDataMemberChanged("sum") instead of RaisePropertyChanged("sum"). RaiseDataMemberChanged() must mark something in the entity as modified, wich was casuing this issue. Thanks IronMan84 for all your help.
Upvotes: 0
Reputation: 16137
Incredibly enough, Julie Lerman just had an amazing MSDN article about this exact issue and why it happens. You can find the article right here.
In Julie's own words:
The reason it happens is that when you use the DbSet.Add method, not only is the state of the root entity marked “Added,” but everything in the graph that the context was not previously aware of is marked Added as well. Even though the developer may be aware that the object has an existing Id value, Entity Framework honors its EntityState (Added) and creates an Insert database command for the object, regardless of the existing Id.
So what's happening in a nutshell here is that when you say Context.OptionUnits.Add(bridge);
, it also thinks that you are trying to add the Option and Unit objects to it as well. Instead, you'll need to use the FKs (as she mentions) and then add it.
I think that that's what you're trying to do in your second attempt there, but I wonder how you're checking to see if it's in SelectedOption.OptionUnits
. Are trying to check it right after the save? In which case it won't show up since that value is cached in memory when it gets pulled by Entity Framework. You would need to try bringing up that object again afterwards.
Upvotes: 3