Saving Data with Entity Framework Core
This section details how to save data to your database using Entity Framework Core (EF Core). Saving data involves adding, updating, and deleting entities and then persisting these changes to the database.
The DbContext
and State Management
EF Core tracks the state of entities within its context. When you fetch an entity, EF Core attaches it to the DbContext
and marks its state as Unchanged
.
When you modify a tracked entity (e.g., change a property value), EF Core automatically detects the change and marks its state as Modified
.
Adding New Entities
To add a new entity, create an instance of your entity class and add it to an appropriate DbSet<TEntity>
property on your DbContext
.
using (var context = new BloggingContext())
{
var newBlog = new Blog { Url = "http://example.com" };
context.Blogs.Add(newBlog);
context.SaveChanges();
}
When SaveChanges()
is called, EF Core generates the necessary SQL commands to insert the new entity into the database.
Modifying Existing Entities
As mentioned, EF Core automatically tracks changes to entities that are already attached to the context. You can simply modify the properties of a tracked entity.
using (var context = new BloggingContext())
{
var existingBlog = context.Blogs.FirstOrDefault(b => b.BlogId == 1);
if (existingBlog != null)
{
existingBlog.Url = "http://newexample.com";
context.SaveChanges();
}
}
Alternatively, you can explicitly mark an entity as modified using context.Entry(entity).State = EntityState.Modified;
. This is particularly useful when dealing with entities that are not currently tracked by the context.
var blogToUpdate = new Blog { BlogId = 2, Url = "http://updatedurl.com" };
using (var context = new BloggingContext())
{
context.Entry(blogToUpdate).State = EntityState.Modified;
context.SaveChanges();
}
Modified
explicitly for an unattached entity, EF Core assumes all properties have been modified. If you only want to update specific properties, consider using context.Attach()
and then marking only the changed properties.
Deleting Entities
To delete an entity, you first need to retrieve it and then mark it for deletion using the Remove()
method on the context.
using (var context = new BloggingContext())
{
var blogToDelete = context.Blogs.FirstOrDefault(b => b.BlogId == 3);
if (blogToDelete != null)
{
context.Blogs.Remove(blogToDelete);
context.SaveChanges();
}
}
Similar to modifications, you can also delete an entity that is not currently tracked by the context by attaching it and setting its state to Deleted
.
var blogToDelete = new Blog { BlogId = 4 };
using (var context = new BloggingContext())
{
context.Entry(blogToDelete).State = EntityState.Deleted;
context.SaveChanges();
}
Saving Multiple Changes
You can perform multiple add, update, and delete operations within a single DbContext
instance and then call SaveChanges()
once to persist all changes efficiently.
using (var context = new BloggingContext())
{
// Add a new blog
context.Blogs.Add(new Blog { Url = "http://anotherblog.com" });
// Update an existing blog
var blogToUpdate = context.Blogs.Find(1);
if (blogToUpdate != null)
{
blogToUpdate.Url = "http://updatedblogurl.com";
}
// Delete a blog
var blogToDelete = context.Blogs.Find(2);
if (blogToDelete != null)
{
context.Blogs.Remove(blogToDelete);
}
context.SaveChanges(); // All changes saved atomically
}
SaveChanges()
, EF Core attempts to save all pending changes in a single database transaction. If any part of the operation fails, the entire transaction is rolled back.
Concurrency Control
Concurrency conflicts can occur when multiple users or processes attempt to modify the same data simultaneously. EF Core provides mechanisms to handle these conflicts.
By default, EF Core uses a "last-in, first-out" strategy. If a conflict is detected during SaveChanges()
, an DbUpdateConcurrencyException
is thrown.
For more sophisticated concurrency handling (e.g., detecting which specific rows caused the conflict or implementing specific resolution strategies), you can configure concurrency tokens (e.g., using a timestamp column).
SaveChanges()
Return Value
The SaveChanges()
method returns an int
representing the number of state entries that were successfully written to the database.