MSDN Documentation

CRUD Operations with Entity Framework

Entity Framework (EF) provides a powerful and intuitive way to perform Create, Read, Update, and Delete (CRUD) operations on your data. EF abstracts away much of the underlying SQL, allowing you to work with your data using .NET objects.

Understanding the DbContext

The central class for interacting with EF is DbContext. It represents a session with the database and allows you to query and save data. You typically derive from DbContext and include a property for each entity set in your model.

Example of a simple DbContext:


using Microsoft.EntityFrameworkCore;

public class MyDbContext : DbContext
{
    public DbSet Products { get; set; }
    public DbSet Categories { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;");
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int CategoryId { get; set; }
    public Category Category { get; set; }
}

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection Products { get; set; }
}
            

Creating Data (Create)

To add new entities to the database, you create instances of your entity classes, add them to the appropriate DbSet, and then call SaveChanges() on the DbContext.


using (var context = new MyDbContext())
{
    var newCategory = new Category { Name = "Electronics" };
    context.Categories.Add(newCategory);

    var newProduct = new Product
    {
        Name = "Laptop",
        Price = 1200.00m,
        Category = newCategory // Or use CategoryId if you don't want to load category first
    };
    context.Products.Add(newProduct);

    context.SaveChanges(); // Executes INSERT statements
}
            

Reading Data (Read)

Querying data is done through LINQ to Entities. You can retrieve all entities, filter them, sort them, and project them into new shapes.

Retrieving all products:


using (var context = new MyDbContext())
{
    var allProducts = context.Products.ToList();
    foreach (var product in allProducts)
    {
        Console.WriteLine($"ID: {product.Id}, Name: {product.Name}, Price: {product.Price}");
    }
}
            

Filtering and sorting:


using (var context = new MyDbContext())
{
    var expensiveProducts = context.Products
                                   .Where(p => p.Price > 500)
                                   .OrderBy(p => p.Name)
                                   .ToList();
}
            

Including related data (using navigation properties):


using (var context = new MyDbContext())
{
    var productsWithCategories = context.Products
                                        .Include(p => p.Category)
                                        .ToList();
    foreach (var product in productsWithCategories)
    {
        Console.WriteLine($"{product.Name} belongs to {product.Category.Name}");
    }
}
            

Updating Data (Update)

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


using (var context = new MyDbContext())
{
    var productToUpdate = context.Products.Find(1); // Find by primary key

    if (productToUpdate != null)
    {
        productToUpdate.Price = 1250.00m;
        productToUpdate.Name = "Gaming Laptop";
        context.SaveChanges(); // Executes UPDATE statement
    }
}
            

For disconnected scenarios (e.g., data received from a web API), you can attach the entity and set its state:


// Assuming 'updatedProduct' is an entity received from somewhere else
// and its Id is already set.
var detachedProduct = new Product { Id = 1, Name = "Updated Name", Price = 1300.00m };
using (var context = new MyDbContext())
{
    context.Entry(detachedProduct).State = EntityState.Modified;
    context.SaveChanges(); // Executes UPDATE statement
}
            

Deleting Data (Delete)

To delete an entity, retrieve it from the database and then call Remove() on the `DbSet` before calling SaveChanges().


using (var context = new MyDbContext())
{
    var productToDelete = context.Products.Find(2); // Find by primary key

    if (productToDelete != null)
    {
        context.Products.Remove(productToDelete);
        context.SaveChanges(); // Executes DELETE statement
    }
}
            

Similar to updates, you can also delete detached entities:


// Assuming 'productToRemove' is an entity with its Id set
var detachedProduct = new Product { Id = 3 };
using (var context = new MyDbContext())
{
    context.Products.Remove(detachedProduct);
    context.SaveChanges(); // Executes DELETE statement
}
            

Transaction Management

DbContext.SaveChanges() by default runs within a database transaction. If you need to perform multiple operations atomically, you can use explicit transactions:


using (var context = new MyDbContext())
{
    using (var transaction = context.Database.BeginTransaction())
    {
        try
        {
            var product = new Product { Name = "New Gadget", Price = 50.00m };
            context.Products.Add(product);
            context.SaveChanges();

            // Perform another operation
            var category = context.Categories.Find(1);
            if (category != null)
            {
                category.Name = "Updated Category";
                context.SaveChanges();
            }

            transaction.Commit(); // If all operations succeed
        }
        catch
        {
            transaction.Rollback(); // If any operation fails
            throw;
        }
    }
}
            

This section covers the fundamental CRUD operations in Entity Framework. For more advanced scenarios, refer to the detailed documentation on querying, relationships, and concurrency.