I recently started using Entity Framework, and it has been kind of a pain to check if I really need to add new records to the database or not.
If the Entity I need to add to the database is already on it, I will know, because I do a query before inserting it, and if it exists, then I keep that instance because I need to use it in some relationships.
Let's suppose my entity name is
The problem comes when an entity isn't in the database, and I do:
Book b = //... modelContainer.AddToBooks(b);
I could easily do:
everytime I add a new entity (no matter what entity it is), and this will work fine, because as I'm inserting one kind of entry at a time, and checking if it already is in the database, I won't have duplication problems.
But what if I want to avoid calling
SaveChanges() so often?
In this question: Is is possible to check if an object is already attached to a data context in Entity Framework?, the author of the question provides a method that kind of helps me in my case, but it does not work if I
Add the object to the context instead of
My question (maybe two, but very related) is: What is the difference between Add and Attach and how can I solve my problem?
Here is an example of the problem I'm having.
I have an entity
Result that has a relationship with two more entities:
I get the data from an external source, so I have to create manually all the entities.
Everytime I need to insert a new
Trainer, I do:
var trainer = Trainer.CreateTrainer(Id)
Then I query the database to see if a trainer with that
Id is already on the database. If it is, then I replace the
trainer variable with the one that is on the database.
If it isn't, I can do two things here:
- Attach the trainer to the context (I can check if it already exists using the key)
- Add the trainer to the context (using
The same process for
Now, when I need to create a new
Result (that contains a
Trainer and a
Horse), I assign the previous trainer & horse to that result instance.
What should I do here to be able to add to the context that new
- If I attach the trainer/horse, then when I attach the result, I get
InvalidOperationException, teling me that the trainer is already on the object context.
- If I add the trainer instead of attaching it, I get another error (can't remember it right now, but it was telling me that a Trainer was already on the database).
The first error is given when attaching the result, and the second one when doing
What I want to avoid here is calling
SaveChanges() everytime I add a new result.
ObjectContext internally tracks all entities which was either loaded by context, attached or added. Only these entities can be modified in database when
SaveChanges is invoked. Each such entity has a
ObjectStateEntry in the
ObjectStateManager. One of the main properties of the
ObjectStateEntry is a
State. The state is of enum type
EntityState which offers these values:
Each entity loaded from the database is in
Unchanged state. Detached is special state. You will not find
ObjectStateEntry with Detached state in the
ObjectStateManager. But if you ask
ObjectStateManager for the
ObjectStateEntry for entity not tracked by the context it will create a new
Now the difference between
Attach- if you call this method
ObjectContextwill start tracking whole object graph (main entity and all related entities). All entities which were not tracked yet will be set to
AddObject- if you call this method
ObjectContextwill also start tracking whole object graph (main entity and all related entities). The difference is that all entities which were not tracked yet will be set to
Addedstate (= new objects which must be set to database).