DbContext API
The DbContext
class is the central hub for interacting with your database in Entity Framework Core.
It represents a session with the database and allows you to query and save data.
Understanding the DbContext
API is fundamental to effectively using Entity Framework Core.
Key Concept: DbContext
A DbContext
instance is a lightweight object that is typically created for a single unit of work.
It manages the database connection, change tracking, and transaction management.
Core Properties
The DbContext
class provides several essential properties for managing your data context:
Property | Description |
---|---|
Database |
Provides access to the underlying database connection and operations. You can use it to execute raw SQL, manage transactions, and more. |
ChangeTracker |
Exposes information about the entities currently being tracked by the context, including their states (Added, Modified, Deleted, Unchanged). |
Model |
Represents the EF Core model for the context, providing access to entity types, properties, and relationships. |
Core Methods
These methods are the primary way you interact with your data through the DbContext
:
Method | Description |
---|---|
Add<TEntity>(TEntity entity) |
Adds a new entity to the context. The entity will be inserted into the database when SaveChanges is called. |
AddRange<TEntity>(IEnumerable<TEntity> entities) |
Adds multiple entities to the context. |
Update<TEntity>(TEntity entity) |
Marks an existing entity as modified. All properties will be updated in the database when SaveChanges is called. |
UpdateRange<TEntity>(IEnumerable<TEntity> entities) |
Marks multiple existing entities as modified. |
Remove<TEntity>(TEntity entity) |
Marks an entity for deletion. The entity will be deleted from the database when SaveChanges is called. |
RemoveRange<TEntity>(IEnumerable<TEntity> entities) |
Marks multiple entities for deletion. |
SaveChanges() |
Persists all pending changes (adds, updates, deletes) to the database. Returns the number of state entries written to the database. |
SaveChangesAsync(CancellationToken cancellationToken = default) |
Asynchronously persists all pending changes to the database. |
Find<TEntity>(params object[] keyValues) |
Finds an entity with the given primary key value. It first checks in the context cache, then queries the database if not found. |
Entry<TEntity>(TEntity entity) |
Gets the EntityEntry<TEntity> object for the given entity. This provides detailed information and control over the entity's state and properties. |
Change Tracking
DbContext
automatically tracks changes to entities. When you retrieve an entity, EF Core monitors it for modifications. The ChangeTracker
property allows you to inspect and manipulate these tracked entities.
Entity States
Entities can be in one of the following states:
Added
: The entity is new and will be inserted.Modified
: The entity has been changed and will be updated.Deleted
: The entity will be removed.Unchanged
: The entity has not been changed.Detached
: The entity is not being tracked by the context.
You can manually control the state of an entity using the Entry
method:
var blog = _context.Blogs.Find(1);
if (blog != null)
{
// Mark as modified explicitly
_context.Entry(blog).State = EntityState.Modified;
// Or, if you only modified specific properties:
// _context.Entry(blog).Property(b => b.Url).IsModified = true;
}
Querying Data
Entities are exposed through DbSet<TEntity>
properties on your DbContext
. You use LINQ to query these sets.
// Get all blogs
var allBlogs = _context.Blogs.ToList();
// Get blogs with a specific URL
var specificBlog = _context.Blogs
.Where(b => b.Url.Contains("example.com"))
.FirstOrDefault();
// Include related data
var blogsWithPosts = _context.Blogs
.Include(b => b.Posts) // Assuming a navigation property named Posts
.ToList();
Executing Raw SQL
For scenarios where LINQ is not sufficient, you can execute raw SQL queries:
var blogsFromSql = _context.Blogs.FromSqlRaw("SELECT * FROM Blogs");
Saving Data
The SaveChanges
method is crucial for persisting your changes. It performs batch operations and handles concurrency.
// Add a new blog
var newBlog = new Blog { Url = "http://newblog.com" };
_context.Blogs.Add(newBlog);
int rowsAffected = _context.SaveChanges(); // Commits the addition
// Update an existing blog
var existingBlog = _context.Blogs.Find(2);
if (existingBlog != null)
{
existingBlog.Url = "http://updatedurl.com";
_context.SaveChanges(); // Commits the update
}
// Delete a blog
var blogToDelete = _context.Blogs.Find(3);
if (blogToDelete != null)
{
_context.Blogs.Remove(blogToDelete);
_context.SaveChanges(); // Commits the deletion
}
Transactions
By default, SaveChanges
runs within a database transaction. If any operation fails, the entire transaction is rolled back, ensuring data consistency.
Configuration
You configure your DbContext
, typically in its constructor, by overriding the OnConfiguring
method or by using dependency injection with ConfigureServices
in ASP.NET Core.
// Example using OnConfiguring
public class MyDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;");
}
// ... other DbContext methods
}
Dependency Injection
In modern applications, especially web applications, DbContext
is typically registered with a dependency injection container and injected into your services rather than configured directly in OnConfiguring
.