Entity Framework SaveChanges
method of DbContext class handles the persisting of data to the database. When we use the SaveChanges
it prepares the corresponding insert
, update
, delete
queries. It then wraps them in a Transaction and sends it to the database. If anyone of the query fails all the statements are rolled back. The Context also manages the entity objects during run time, which includes populating objects with data from a database, change tracking, etc.
Source Code:
The source code of this project available in GitHub.
Table of Contents
DbContext
The DbContext
is primarily responsible managing the entities.
- It transforms the Entity Framework Queries to SQL Queries and sends it to the database.
- The Context translates the database results back to entities. we call this process as the materialization
- It allows us to create new entities, by adding them to the context
- Keep track of the changes made to the entities using ChangeTracker
- Save changes made to the entities in the database. By calling the
SaveChanges
method.
SaveChanges
The SaveChanges
method of the DbContext
saves changes to the made to the entities to the database. The following example shows how to add, modify & remove data using the SaveChanges
method
Add Record
Create a new entity and use the Add
method to add the entity to the context. You can then call the SaveChanges
to persist the data to the database.
1 2 3 4 5 6 7 8 9 10 11 | using (EFContext db = new EFContext()) { Department dep = new Department(); dep.Name = "Secuirty"; db.Departments.Add(dep); db.SaveChanges(); } |
Update Record
Query and get the entity to, which you want to modify. Make the necessary changes and call the SaveChanges
1 2 3 4 5 6 7 8 | using (EFContext db = new EFContext()) { dep = db.Departments.Where(d => d.Name == "Accounts").First(); dep.Descr = "This is Accounts Department"; db.SaveChanges(); } |
Delete Record
Similarly use the Remove
method to mark the entity for deletion. Calling the SaveChanges
will delete the entity from the database
1 2 3 4 5 6 7 8 | using (EFContext db = new EFContext()) { dep = db.Departments.Where(d => d.Name == "Accounts").First(); db.Departments.Remove(dep); db.SaveChanges(); } |
Connected & Disconnected Scenarios
The SaveChanges
method of the DbContext
prepares the Insert
, Update
& Delete
Queries. It does so by tracking the changes to each of the entities’ context is tracking.
Whenever we query the database for entities, the context retrieves them and mark the entity as Unchanged
. The ChangeTracker property of the DbContext
keeps track of the entities. Whenever we make update/add or delete the entities it mark them as Updated
, Added
or Deleted
etc.
When we call the SaveChanges
method, it loops through all the entities it is tracking checking for their states. Depending on their states it prepares the Insert
,Update
or Delete
SQL statements. Before sending it to the database it wraps them inside a Single Transaction and sends it to the database. It rollbacks all the changes if anyone of the statement fails.
But for the SaveChanges
to work, the Context must correctly mark the entity as Updated
, Added
or Deleted
etc. But if we close the context and make changes to the entity, those will not be tracked by the context. Hence we have two possibilities here.
- Connected Scenario
- Disconnected Scenario
Connected Scenario
Connected Scenario is when we do not close the context, during the lifetime of the entities.
If the context is open, then the ChangeTracker
can easily keep track of the changes made to the entities. It now knows which entity is added/modified or deleted. During the SaveChanges
method call, the Context generates the correct SQL query (insert, update or delete) depending on the state of the entity (added, modified or deleted)
The Code below shows the SaveChanges
in Connected Scenario. First, we create the Context using the Using
statement. We then retrieve Department
entity from the database. We then modify the Descr
property of the entity. We can also add a new entity, update the entity, and delete an entity. Finally, when we call the SaveChanges
method to persist the data back to the database. The entire operation takes place in the same context. We do not close or destroy the Context between the retrieval and saving of the entities.
1 2 3 4 5 6 7 8 | using (EFContext db = new EFContext()) { dep = db.Departments.Where(d => d.Name == "Accounts").First(); dep.Descr = "This is Accounts Department"; db.SaveChanges(); } |
Disconnected Scenario
The connected scenario is not always possible in real life apps.
For Example, in a web application, the user requests for the
entity. We create a new instance of the context, fetch the data, and send the data back to the user. The Server will close the context & disposes of. Now, when the user updates the Department
Department
entity and returns it back. Now we create a new instance of the context. This newly created context knows nothing about the
entity. It does not know whether it is a new entity or an existing entity, where the user has made modifications.Department
Here, when we call the SaveChanges
the it wont update anything in the database. This is a Disconnected Scenario.
To update this entity we need to attach
the Employee
to the context and inform it to mark its status as Modified
using the db.Entry
method. Now if we call the SaveChanges
, the context will send an update
query to the database.
The example code is shown below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | { Department dep; using (EFContext db = new EFContext()) { dep = db.Departments.Where(d => d.Name == "Purchase").First(); } //Context Closed dep.Descr = "Purchase Department-Disconnected Scenario"; //New context using (EFContext db = new EFContext()) { db.Entry(dep).State = System.Data.Entity.EntityState.Modified; db.SaveChanges(); } } |
References
Read More