Working with Entities
Working with entities in Entity Framework (EF) involves understanding how EF represents your data and how you can interact with it. Entities are essentially .NET objects that map to tables in your database. EF provides a rich set of features to create, read, update, and delete (CRUD) these entities seamlessly.
Entity States
Each entity instance within an EF context has a specific state. This state helps EF track changes made to the entity. The common states are:
- Added: The entity is new and will be inserted into the database when
SaveChanges
is called. - Unchanged: The entity has been retrieved from the database and has not been modified since.
- Modified: The entity's properties have been changed since it was retrieved from the database and will be updated.
- Deleted: The entity has been marked for deletion and will be removed from the database.
- Detached: The entity is not being tracked by the context.
Tracking Changes
An DbContext
instance tracks entities that are retrieved from the database or added to the context. This tracking is crucial for detecting changes and generating the appropriate SQL commands for updates and inserts.
You can explicitly set the state of an entity using the Entry()
method of your DbContext
:
var product = new Product { Id = 1, Name = "Old Name" };
context.Entry(product).State = EntityState.Modified;
CRUD Operations
Creating Entities (Adding)
To add a new entity, create an instance of your entity class and add it to the appropriate DbSet
on your DbContext
.
var newProduct = new Product
{
Name = "New Gadget",
Price = 99.99m
};
context.Products.Add(newProduct);
context.SaveChanges(); // Inserts the new product into the database
Reading Entities (Querying)
Querying entities is typically done using LINQ to Entities. The DbContext
translates your LINQ queries into SQL.
// Get all products
var allProducts = context.Products.ToList();
// Get a specific product by ID
var productById = context.Products.Find(1);
// Filter products
var expensiveProducts = context.Products.Where(p => p.Price > 50).ToList();
Updating Entities
When you retrieve an entity from the context, EF starts tracking it. Modifying its properties directly will mark it as Modified
automatically.
var productToUpdate = context.Products.Find(2);
if (productToUpdate != null)
{
productToUpdate.Name = "Updated Widget";
productToUpdate.Price = 75.50m;
context.SaveChanges(); // Updates the product in the database
}
If an entity is detached, you need to reattach it and mark it as modified:
var detachedProduct = new Product { Id = 3, Name = "Modified Name" };
context.Products.Attach(detachedProduct);
context.Entry(detachedProduct).State = EntityState.Modified;
context.SaveChanges();
Deleting Entities
To delete an entity, retrieve it from the context and then call the Remove()
method on the DbSet
.
var productToDelete = context.Products.Find(4);
if (productToDelete != null)
{
context.Products.Remove(productToDelete);
context.SaveChanges(); // Deletes the product from the database
}
SaveChanges()
on the DbContext
to persist your changes to the database. If an exception occurs during SaveChanges()
, the entire transaction will be rolled back.
Concurrency Handling
Concurrency conflicts can occur when multiple users or processes try to modify the same data simultaneously. Entity Framework provides mechanisms to handle these conflicts.
- Optimistic Concurrency: EF typically uses optimistic concurrency. It checks whether the data has changed since it was loaded. If it has, a
DbUpdateConcurrencyException
is thrown. You can then decide how to resolve the conflict.
To implement optimistic concurrency, you can use row versioning (e.g., a timestamp column) or check all concurrency tokens. EF automatically detects and handles this for properties marked with the [Timestamp]
attribute or using the IsRowVersion()
configuration.
Managing State with Change Tracking Proxies
By default, EF creates proxy classes for your entities. These proxies automatically update the entity's state when properties are changed, simplifying change tracking.
// Assuming Change Tracking Proxies are enabled
var product = context.Products.Find(5);
product.Price = 120.00m; // EF automatically marks the product as Modified
context.SaveChanges();