MSDN Documentation

Microsoft Developer Network

Entity Framework CRUD Operations

This document provides a comprehensive guide to performing Create, Read, Update, and Delete (CRUD) operations using Entity Framework Core.

Entity Framework Core (EF Core) simplifies data access in .NET applications by providing an Object-Relational Mapper (ORM). CRUD operations are fundamental to any data-driven application, and EF Core makes these tasks straightforward and efficient.

Understanding the DbContext

The core of EF Core interaction is the DbContext class. It represents a session with the database and allows you to query and save data. You'll typically create a derived context class that exposes DbSet<TEntity> properties for each entity in your model.

// Example 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=BloggingEF;Trusted_Connection=True;");
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public 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 Blog Blog { get; set; }
}

Create (Adding New Data)

To add new entities to the database, you first instantiate your DbContext, create an instance of your entity, add it to the appropriate DbSet, and then call SaveChanges().

using (var context = new BloggingContext())
{
    var newBlog = new Blog { Url = "http://example.com/blog" };
    context.Blogs.Add(newBlog);
    context.SaveChanges(); // Inserts the new blog into the database
}

Read (Querying Data)

Reading data is typically done using LINQ to Entities. You can query directly from your DbSet properties.

Retrieving a Single Entity

Use methods like Find() (which first checks the local cache) or FirstOrDefaultAsync().

using (var context = new BloggingContext())
{
    // Find by primary key
    var blog = context.Blogs.Find(1);

    // Find first matching a condition
    var firstBlog = context.Blogs.FirstOrDefault(b => b.Url.Contains("example"));
}

Retrieving Multiple Entities

Iterate over the DbSet or use LINQ to filter and project.

using (var context = new BloggingContext())
{
    var allBlogs = context.Blogs.ToList(); // Retrieves all blogs

    var blogsWithPosts = context.Blogs
        .Where(b => b.Posts.Any())
        .ToList();
}

Update (Modifying Existing Data)

To update an entity, you first retrieve it from the database, modify its properties, and then call SaveChanges(). EF Core tracks changes automatically.

using (var context = new BloggingContext())
{
    var blogToUpdate = context.Blogs.Find(1);
    if (blogToUpdate != null)
    {
        blogToUpdate.Url = "http://updated-example.com/blog";
        context.SaveChanges(); // Updates the blog in the database
    }
}
If you retrieve an entity, detach it from the context, modify it, and then reattach it, you might need to explicitly mark it as modified. However, for typical update scenarios within the same DbContext instance, EF Core handles it automatically.

Delete (Removing Data)

Similar to updating, you retrieve the entity you want to delete, then call Remove() on the DbContext, followed by SaveChanges().

using (var context = new BloggingContext())
{
    var blogToDelete = context.Blogs.Find(2);
    if (blogToDelete != null)
    {
        context.Blogs.Remove(blogToDelete);
        context.SaveChanges(); // Deletes the blog from the database
    }
}

Best Practices

Asynchronous Operations
Bulk Operations

Asynchronous CRUD Operations

Leveraging asynchronous programming with EF Core can significantly improve the responsiveness and scalability of your application, particularly in I/O-bound scenarios like database access.

using (var context = new BloggingContext())
{
    var newPost = new Post { Title = "Async Post", Content = "This is an async example.", BlogId = 1 };
    await context.Posts.AddAsync(newPost);
    await context.SaveChangesAsync(); // Asynchronously saves changes
}

using (var context = new BloggingContext())
{
    var blog = await context.Blogs.FirstOrDefaultAsync(b => b.BlogId == 1);
    if (blog != null)
    {
        // ... modify blog ...
        await context.SaveChangesAsync();
    }
}

Bulk Operations with EF Core Extensions

For very large numbers of entities, consider using third-party libraries like EF Core.BulkExtensions for significantly faster bulk insert, update, and delete operations.

Example using EF Core.BulkExtensions (requires installation via NuGet):

// using EFCore.BulkExtensions;

// List<Blog> blogsToAdd = ...;
// await context.BulkInsertAsync(blogsToAdd);

// List<Post> postsToUpdate = ...;
// await context.BulkUpdateAsync(postsToUpdate);

// List<int> blogIdsToDelete = ...;
// await context.Blogs.Where(b => blogIdsToDelete.Contains(b.BlogId)).BulkDeleteAsync();