Working with Data
This section delves into the practical aspects of interacting with your data using Entity Framework. We'll cover common operations like creating, reading, updating, and deleting (CRUD) entities, as well as managing relationships and handling concurrency.
CRUD Operations
Entity Framework simplifies data manipulation through its DbContext
and entity objects. The following operations demonstrate basic CRUD:
Creating a New Entity
To add a new record, create an instance of your entity class and add it to the appropriate DbSet
within your DbContext
.
using (var context = new YourDbContext())
{
var newProduct = new Product
{
Name = "New Gadget",
Price = 99.99m
};
context.Products.Add(newProduct);
context.SaveChanges();
}
Reading Entities
You can retrieve entities using LINQ queries against your DbSet
s. Entity Framework translates these queries into SQL.
using (var context = new YourDbContext())
{
var product = context.Products.FirstOrDefault(p => p.Id == 1);
if (product != null)
{
Console.WriteLine($"Product Name: {product.Name}");
}
var allProducts = context.Products.ToList();
}
Updating an Entity
Modify the properties of an entity retrieved from the context, and then call SaveChanges()
. Entity Framework tracks these changes automatically.
using (var context = new YourDbContext())
{
var productToUpdate = context.Products.Find(1);
if (productToUpdate != null)
{
productToUpdate.Price = 109.99m;
context.SaveChanges();
}
}
Deleting an Entity
To remove an entity, retrieve it first and then call the Remove()
method on the DbSet
.
using (var context = new YourDbContext())
{
var productToDelete = context.Products.Find(1);
if (productToDelete != null)
{
context.Products.Remove(productToDelete);
context.SaveChanges();
}
}
Managing Relationships
Entity Framework supports various relationships, including one-to-many, many-to-many, and one-to-one. When you load an entity, related entities can often be loaded implicitly or explicitly.
Loading Related Data (Eager Loading, Lazy Loading, Explicit Loading)
- Eager Loading: Use
Include()
to load related entities in the same query.
var customerWithOrders = context.Customers
.Include(c => c.Orders)
.FirstOrDefault(c => c.Id == 1);
Entry().Collection()
or Entry().Reference()
to load related data after the main entity has been loaded.Concurrency Handling
Concurrency occurs when multiple users try to modify the same data simultaneously. Entity Framework provides mechanisms to detect and resolve these conflicts.
Optimistic Concurrency
This is the most common approach. It involves versioning or timestamping data. If the data has changed since it was last read, an exception is thrown.
To implement optimistic concurrency, mark a property in your entity with the [ConcurrencyCheck]
attribute or configure it in OnModelCreating
. When SaveChanges
fails due to a concurrency conflict, a DbUpdateConcurrencyException
is thrown.
// In your entity
public class Product
{
public int Id { get; set; }
[ConcurrencyCheck]
public byte[] RowVersion { get; set; } // Or DateTime Stamp
public string Name { get; set; }
public decimal Price { get; set; }
}
// Handling the exception
try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
// Handle the concurrency conflict, e.g., reload data and reapply changes
var entry = ex.Entries.Single();
var databaseValues = entry.GetDatabaseValues();
if (databaseValues == null)
{
// The entity was deleted by another user
Console.WriteLine("The entity has been deleted by another user.");
}
else
{
// Reload the original and database values
var databaseEntry = entry.ToRow(databaseValues);
var clientValues = (Product)entry.Entity;
// Compare the client's values with the database's values
if (databaseEntry.Name != clientValues.Name)
Console.WriteLine("The product name has been changed by another user.");
if (databaseEntry.Price != clientValues.Price)
Console.WriteLine("The product price has been changed by another user.");
// Refresh original values and re-attach the entity
entry.OriginalValues.SetValues(databaseValues);
Console.WriteLine("Concurrency conflict detected and handled.");
// Optionally, re-throw or prompt user for resolution
}
}