Entity Framework: Saving Data
This document explains how to save data to your database using Entity Framework Core. Saving data involves adding new entities, modifying existing ones, and deleting entities from your database.
Adding New Entities
To add a new entity, you typically instantiate a new object, populate its properties, and then attach it to your DbContext
. The DbContext.Add()
method is used for this purpose.
Example: Adding a new blog
using (var context = new BlogContext())
{
var newBlog = new Blog { Url = "https://devblogs.microsoft.com/" };
context.Blogs.Add(newBlog);
context.SaveChanges();
}
When SaveChanges()
is called, Entity Framework generates the appropriate SQL INSERT
statement for the new blog entry.
Modifying Existing Entities
Entity Framework tracks changes to entities that are already being tracked by the context. When you retrieve an entity from the database, its state is initially Unchanged
.
Example: Updating a blog's URL
using (var context = new BlogContext())
{
var existingBlog = context.Blogs.FirstOrDefault(b => b.BlogId == 1);
if (existingBlog != null)
{
existingBlog.Url = "https://devblogs.microsoft.com/dotnet/";
context.SaveChanges();
}
}
In this case, Entity Framework detects that the Url
property has changed and generates a SQL UPDATE
statement.
Modifying Detached Entities
If you have an entity that is not currently tracked by the context (e.g., it was created manually or retrieved in a previous context lifetime), you need to explicitly mark it as modified.
using (var context = new BlogContext())
{
var detachedBlog = new Blog { BlogId = 1, Url = "https://new.url.com/" };
context.Entry(detachedBlog).State = EntityState.Modified;
context.SaveChanges();
}
Note: When using EntityState.Modified
on a detached entity, all properties will be updated. If you only want to update specific properties, use context.Attach(entity)
and then mark only the modified properties.
Deleting Entities
To delete an entity, you first retrieve it (or have a reference to it) and then use the DbContext.Remove()
method.
Example: Deleting a blog
using (var context = new BlogContext())
{
var blogToDelete = context.Blogs.FirstOrDefault(b => b.BlogId == 2);
if (blogToDelete != null)
{
context.Blogs.Remove(blogToDelete);
context.SaveChanges();
}
}
Calling SaveChanges()
will result in a SQL DELETE
statement being executed.
Saving Multiple Changes
You can perform multiple operations (add, modify, delete) within a single context and save them all at once with a single call to SaveChanges()
. Entity Framework will generate the appropriate batch of SQL commands.
Example: Batch operations
using (var context = new BlogContext())
{
// Add a new blog
var newBlog = new Blog { Url = "https://new.blog.site/" };
context.Blogs.Add(newBlog);
// Update an existing blog
var existingBlog = context.Blogs.Find(1);
if (existingBlog != null)
{
existingBlog.Title = "Updated Title";
}
// Delete a blog
var blogToDelete = context.Blogs.Find(3);
if (blogToDelete != null)
{
context.Blogs.Remove(blogToDelete);
}
context.SaveChanges(); // All changes are applied in one transaction
}
Concurrency Conflicts
Concurrency conflicts occur when multiple users or processes try to modify the same data simultaneously. Entity Framework provides strategies to handle these conflicts.
By default, Entity Framework uses a "last-in, first-out" approach, where the last save operation wins. For more robust handling, you can implement optimistic concurrency checking using row versioning or by checking specific properties.
Tip: For complex scenarios or critical data, consider implementing custom concurrency resolution logic to inform users of conflicts and provide options for reconciliation.
Handling Concurrency Exceptions
try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
// Handle the concurrency exception, e.g., reload data or inform the user
Console.WriteLine("A concurrency conflict occurred.");
// Optionally, you can reload the entity from the database and merge changes
var entry = ex.Entries.Single();
var databaseValues = await entry.GetDatabaseValuesAsync();
if (databaseValues == null)
{
Console.WriteLine("The entity has been deleted by another user.");
}
else
{
var databaseEntry = context.Entry(entry.Entity);
databaseEntry.OriginalValues.SetValues(databaseValues);
Console.WriteLine("The entity has been modified by another user. Please review the changes.");
// Prompt user for action, or implement auto-merge logic
}
}