Entity Framework Core

Introduction to Entity Framework Core

Entity Framework Core (EF Core) is a modern, cross-platform, extensible data access technology for .NET. It is a rewrite of the popular Entity Framework and is designed to be more lightweight, modular, and performant. EF Core allows developers to work with databases using .NET objects, abstracting away much of the complexity of direct database interaction.

It maps your .NET classes to database tables and provides features like LINQ querying, change tracking, and relationship management, significantly streamlining data persistence in your applications.

Core Concepts

Understanding the fundamental building blocks of EF Core is crucial for effective usage.

DbContext

The DbContext is the primary class representing a session with the database. It's the gateway to querying and saving data. You typically create a derived context class that inherits from DbContext and exposes DbSet<TEntity> properties for each entity type you want to interact with.


using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> 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 class Category {
    public int Id { get; set; }
    public string Name { get; set; }
}
                

Entity Types

An entity type represents a type of object that can be persisted in the database. These are typically represented by your domain classes (POCOs - Plain Old CLR Objects) that map to database tables. EF Core automatically discovers entity types by looking for properties of type DbSet<TEntity> on your derived DbContext.

DbSet<TEntity>

A DbSet<TEntity> property on your DbContext represents a collection of all entities of a given type in the store. It's used for querying and, through the DbContext, for adding, deleting, and modifying entities.

For example, Products in the AppDbContext above is a DbSet<Product>.

Model Configuration

EF Core uses conventions to map your entities to the database. However, you often need to provide explicit configuration to customize aspects like table names, column names, primary keys, relationships, and data types. This can be done using Data Annotations or the Fluent API.

Using Data Annotations


using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

public class Product
{
    [Key]
    public int ProductId { get; set; } // Renamed and marked as Key

    [Required] // Makes the Name column NOT NULL
    [MaxLength(100)] // Sets the VARCHAR/NVARCHAR length
    public string Name { get; set; }

    [Column(TypeName = "decimal(18, 2)")] // Explicitly sets the SQL data type
    public decimal Price { get; set; }

    public int CategoryId { get; set; }
    public Category Category { get; set; }
}
                

Using the Fluent API (via OnModelCreating)


using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    // ... DbSets and OnConfiguring ...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().ToTable("Products"); // Maps Product to "Products" table
        modelBuilder.Entity<Product>().HasKey(p => p.ProductId); // Explicitly set primary key

        modelBuilder.Entity<Product>()
            .Property(p => p.Name)
            .IsRequired()
            .HasMaxLength(100);

        modelBuilder.Entity<Product>()
            .Property(p => p.Price)
            .HasColumnType("decimal(18, 2)");

        // Define a one-to-many relationship
        modelBuilder.Entity<Product>()
            .HasOne(p => p.Category) // Product has one Category
            .WithMany(c => c.Products) // Category has many Products
            .HasForeignKey(p => p.CategoryId); // FK in Product table
    }
}

public class Category {
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Product> Products { get; set; } // Navigation property
}
                

Getting Started with EF Core

To start using EF Core, you'll need to install the relevant NuGet packages.

  1. Install the EF Core runtime:
  2. dotnet add package Microsoft.EntityFrameworkCore
  3. Install the database provider: (e.g., for SQL Server)
  4. dotnet add package Microsoft.EntityFrameworkCore.SqlServer
  5. Install tools for migrations:
  6. dotnet add package Microsoft.EntityFrameworkCore.Tools

Once installed, you can define your DbContext, entity classes, and then use EF Core tools to generate migrations and update your database schema.

Common Scenarios

  • Querying Data: Use LINQ to query entities. EF Core translates LINQ queries into SQL.
  • Adding Data: Attach new entities to the DbContext and call SaveChanges().
  • Updating Data: Fetch an entity, modify its properties, and call SaveChanges(). EF Core tracks the changes.
  • Deleting Data: Attach or retrieve an entity, mark it for deletion using DbContext.Remove(), and call SaveChanges().
  • Relationships: Define navigation properties to model relationships (one-to-one, one-to-many, many-to-many).
Key Takeaway: EF Core abstracts database operations, allowing developers to focus on business logic using familiar .NET objects and LINQ.