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; }
}
            
Note: The 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();
    }
}
            
Tip: For performance, batching multiple operations (additions, updates, deletions) and calling 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:

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();
}
            

Further Reading