Entity Framework Core Data Access
This section delves into the core concepts and techniques for accessing data using Entity Framework Core (EF Core). EF Core is a modern, cross-platform Object-Relational Mapper (ORM) for .NET that enables developers to work with databases using .NET objects, eliminating the need for most of the data-access code they typically have to write.
The DbContext
The heart of EF Core is the DbContext
class. It represents a session with the database and can be used to query and save data. You typically create a class that derives from DbContext
and represents your entity data and the ability to query and save data from a particular database.
Defining Your DbContext
Here's a simple example of a DbContext
:
using Microsoft.EntityFrameworkCore;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=BloggingEFCore;Trusted_Connection=True;");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
}
DbSet<TEntity>
properties on your context class represent collections of entities in the database. EF Core uses these to infer the schema.
Working with DbSets
DbSet<TEntity>
properties allow you to query and manipulate collections of a specific entity type. You can access instances of these properties from your DbContext
.
Querying Data
To query data, you access the DbSet<TEntity>
property and then use LINQ to specify your query criteria.
using (var context = new BloggingContext())
{
var blogs = context.Blogs.Where(b => b.Url.Contains("example.com")).ToList();
foreach (var blog in blogs)
{
Console.WriteLine(blog.Url);
}
}
Saving Data
EF Core tracks changes made to entities that are retrieved from the context. When you call SaveChanges()
or SaveChangesAsync()
, EF Core determines what needs to be inserted, updated, or deleted in the database.
Adding New Entities
using (var context = new BloggingContext())
{
var newBlog = new Blog { Url = "http://new-blog.example.com" };
context.Blogs.Add(newBlog);
context.SaveChanges();
}
Updating Entities
When you retrieve an entity, modify its properties, and then call SaveChanges()
, EF Core automatically detects and applies these changes.
using (var context = new BloggingContext())
{
var existingBlog = context.Blogs.Find(1); // Assuming blog with ID 1 exists
if (existingBlog != null)
{
existingBlog.Url = "http://updated-blog.example.com";
context.SaveChanges();
}
}
Deleting Entities
using (var context = new BloggingContext())
{
var blogToDelete = context.Blogs.Find(2); // Assuming blog with ID 2 exists
if (blogToDelete != null)
{
context.Blogs.Remove(blogToDelete);
context.SaveChanges();
}
}
SaveChanges()
once is generally more efficient than calling it after each individual operation.
Entity States
EF Core tracks the state of each entity within the context. The common states are:
- Added: The entity will be inserted into the database.
- Unchanged: The entity has not been modified since it was retrieved or attached.
- Modified: The entity's properties have been changed.
- Deleted: The entity will be deleted from the database.
- Detached: The entity is not being tracked by the context.
Attaching and Detaching Entities
You can manually attach entities to a context if they were not loaded by it. This is useful when working with disconnected scenarios.
// Assuming 'detachedBlog' was created outside the current context
using (var context = new BloggingContext())
{
// Mark the entity as modified so EF Core knows to update it
context.Attach(detachedBlog);
context.Entry(detachedBlog).State = EntityState.Modified;
context.SaveChanges();
}