Reputation: 2788
The Problem
I'm using Entity Framework to add a complex object model to the database. I'm encountering an issue where I try to insert a child object that EF is also trying to insert the parent object, which is causing an integrity issue in the database.
Explanation
For my example, let's assume we have two tables:
A Shop can have many ShopPerformance entries, the ShopPerformance must have a Shop, and the Shop record already exists in the database (so EF should be leaving it alone and focusing on the ShopPerformance).
In my example, I am attempting to add the ShopPerformance only (in this case the instance of ShopPerformance is called "performance":
this.db.Entry(performance).State = System.Data.EntityState.Added;
this.db.SaveChanges();
When I call SaveChanges(), EF is trying to insert the Shop as well, which causes a constraint error in the database as it has constraints to prevent duplicate entries (based on the shop's name).
Things I've Tried
I've tried setting the Shop property in ShopPerformance to null to stop EF from doing things I don't want to do (it still has the ShopID as a separate property). First I tried:
Shop theShop = performance.Shop;
performance.Shop = null;
this.db.Entry(performance).State = System.Data.EntityState.Added;
this.db.SaveChanges();
performance.Shop = theShop;
In this scenario, EF somehow re-establishes the link between shop and performance and tries to insert shop again.
Then I tried:
Shop theShop = performance.Shop;
this.db.Entry(performance).Entity.Shop = null;
this.db.Entry(performance).State = System.Data.EntityState.Added;
this.db.SaveChanges();
this.db.Entry(performance).Entity.Shop = theShop;
This causes null reference exceptions.
Desired Resolution
I'm looking for a way to insert my performance object without EF fiddling around with the Shop. This is completely breaking my work right now.
TL;DR
I want Entity Framework to Insert/Update ONLY the object I have told it to and none of the related objects. How can I do this?
Upvotes: 2
Views: 1764
Reputation: 14640
You are working with disconnected object, both performance
and performance.Shop
are entities that are not tracked by EF, and EF has no idea what is the status of performance.Shop
.
When adding new performance
with existing performance.Shop
, EF doesn't know that performance.Shop
is an existing entity, and EF will mark all un-tracked objects in the graph as Added
too.
The reason it happens is that when you use the DbSet.Add method (that is, Screencasts.Add), 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. - MSDN
What you need to do is.
If you have the foreign key association, you could just assign the id instead of the reference.
performance.ShopId = performance.Shop.Id;
performance.Shop = null;
this.db.Entry(performance).State = System.Data.EntityState.Added;
this.db.SaveChanges();
Or you need to let EF knows that performance.Shop
is an existing entity by attaching (status = Unchanged
) it first to the context.
this.db.Entry(performance.Shop).State = EntityState.Unchanged;
this.db.Entry(performance).State = EntityState.Added;
this.db.SaveChanges();
Upvotes: 5
Reputation: 6293
Did you tried:
var shop = this.db.shops.Find(id);
shop.Performances.Add(new Performance());
this.db.SaveChanges();
Or
this.db.performances.Add(new Performance() { ShopId = id });
this.db.SaveChanges();
Upvotes: 1