Saving Data with Entity Framework Core
Entity Framework Core (EF Core) provides powerful mechanisms for persisting your application's data to a database. This document guides you through the process of saving data, including adding new entities, updating existing ones, and deleting records.
Adding New Entities
To add a new entity to your database context, you typically create an instance of your entity class and then attach it to the context using the appropriate DbSet.
Using Add()
The Add()
method marks an entity as "added". When SaveChanges()
is called, EF Core will generate an `INSERT` statement for this entity.
using (var context = new MyDbContext())
{
var newProduct = new Product
{
Name = "Super Gadget",
Price = 99.99m
};
context.Products.Add(newProduct); // Or context.Add(newProduct);
context.SaveChanges();
Console.WriteLine($"New product added with ID: {newProduct.Id}");
}
Adding Multiple Entities
You can add multiple entities efficiently using AddRange()
.
using (var context = new MyDbContext())
{
var product1 = new Product { Name = "Widget", Price = 10.00m };
var product2 = new Product { Name = "Gizmo", Price = 25.50m };
context.Products.AddRange(product1, product2); // Or context.AddRange(product1, product2);
context.SaveChanges();
}
Updating Existing Entities
EF Core's change tracker is central to updating entities. When you retrieve an entity from the database and modify its properties, EF Core detects these changes automatically.
Modifying Properties
Simply fetch the entity, change its properties, and call SaveChanges()
. EF Core will generate an `UPDATE` statement for the modified properties.
using (var context = new MyDbContext())
{
var productToUpdate = context.Products.Find(1); // Assuming product with ID 1 exists
if (productToUpdate != null)
{
productToUpdate.Price = 11.50m;
productToUpdate.Name = "Updated Widget";
context.SaveChanges(); // Generates an UPDATE statement
Console.WriteLine("Product updated successfully.");
}
}
Marking Entities as Modified
In scenarios where EF Core might not automatically detect a change (e.g., if you are working with an entity that wasn't initially tracked by the context), you can explicitly mark it as modified.
using (var context = new MyDbContext())
{
var detachedProduct = new Product
{
Id = 2, // Assume this ID already exists in the database
Name = "Gizmo Reborn",
Price = 26.00m
};
context.Entry(detachedProduct).State = EntityState.Modified;
context.SaveChanges(); // Generates an UPDATE statement
}
Deleting Entities
Deleting entities is a straightforward process. You typically retrieve the entity you wish to delete and then use the Remove()
or RemoveRange()
methods.
Using Remove()
The Remove()
method marks an entity for deletion. When SaveChanges()
is called, EF Core generates a `DELETE` statement.
using (var context = new MyDbContext())
{
var productToDelete = context.Products.Find(3); // Assuming product with ID 3 exists
if (productToDelete != null)
{
context.Products.Remove(productToDelete); // Or context.Remove(productToDelete);
context.SaveChanges();
Console.WriteLine("Product deleted successfully.");
}
}
Using RemoveRange()
To delete multiple entities efficiently, use RemoveRange()
.
using (var context = new MyDbContext())
{
var productsToDelete = context.Products.Where(p => p.Price < 5.00m).ToList();
context.Products.RemoveRange(productsToDelete); // Or context.RemoveRange(productsToDelete);
context.SaveChanges();
}
Transactions and Concurrency
SaveChanges()
operations are transactional by default. If any part of the operation fails, the entire transaction is rolled back.
Concurrency Conflicts
Concurrency conflicts can occur when two users try to modify the same data simultaneously. EF Core offers strategies to handle these conflicts, such as:
- Optimistic Concurrency: Using row versioning or timestamp columns.
- Client Wins: The changes from the client application overwrite the database changes.
- Database Wins: The database changes overwrite the client changes.
You can configure these strategies in your DbContext
configuration.
Best Practices
- Use
AddRange()
andRemoveRange()
for bulk operations. - Leverage EF Core's change tracking for automatic updates whenever possible.
- Be mindful of N+1 query problems when loading related data. Use eager loading (
Include()
) or explicit loading appropriately. - Implement robust error handling and concurrency conflict resolution strategies.
- Consider using database transaction scopes for complex multi-operation persistence.