MSDN Documentation

Entity Framework Core Model

This document provides a comprehensive overview of how to define and configure your data model when using Entity Framework Core (EF Core).

Understanding the EF Core Model

The EF Core model represents your application's domain model and how it maps to your database schema. EF Core uses conventions and explicit configuration to discover and understand your model. The core components of an EF Core model are:

  • Entities: Plain Old CLR Objects (POCOs) that represent tables in your database.
  • Entity Types: EF Core's representation of your entity classes, including their properties and relationships.
  • Properties: Attributes of your entities that map to columns in your database tables.
  • Relationships: How your entities are connected (e.g., one-to-many, one-to-one, many-to-many).
  • Primary Keys: Properties that uniquely identify an entity instance.
  • Foreign Keys: Properties that establish relationships between entities.
  • Navigation Properties: Properties that allow you to navigate between related entities.

Example Entity Model

Consider a simple blogging application with authors and posts.

Entity Framework Core Model Diagram Example

In this example:

  • Author and Post are entity types.
  • AuthorId and PostId are primary keys.
  • AuthorId in Post is a foreign key linking to Author.
  • Posts in Author and Author in Post are navigation properties.

Defining Your Model

You can define your EF Core model in two primary ways:

1. Convention-Based Modeling

EF Core uses a set of conventions to automatically discover your model. By following these conventions, you often don't need to write explicit configuration code. For example:

  • Classes that are not abstract and have a public, parameterless constructor are treated as entity types.
  • Properties with a public getter and setter are mapped to columns.
  • Properties named Id or ClassNameId are recognized as primary keys.
  • Properties ending with Id are recognized as foreign keys.
  • Collections (e.g., List<Post>) are treated as the "many" side of a one-to-many relationship.

Here's a typical entity definition:

// Example: Author Entity
public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Post> Posts { get; set; }
}

// Example: Post Entity
public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int AuthorId { get; set; } // Foreign Key
    public Author Author { get; set; } // Navigation Property
}

2. Data Annotations

You can use attributes (data annotations) directly on your entity classes to configure aspects of your model that conventions don't cover or to override convention-based behavior.

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

public class Product
{
    [Key] // Explicitly marks Id as the primary key
    public int ProductId { get; set; }

    [Required] // Makes the Name column NOT NULL
    [StringLength(100)] // Limits the length of the Name column
    public string Name { get; set; }

    [Column(TypeName = "decimal(18, 2)")] // Specifies the database column type
    public decimal Price { get; set; }

    [ForeignKey("Category")] // Explicitly defines the foreign key
    public int CategoryId { get; set; }
    public Category Category { get; set; }
}

3. Fluent API

For more complex configurations, or when you prefer to keep configuration separate from your entities, the Fluent API is the most powerful option. This is done by overriding the OnModelCreating method in your DbContext.

using Microsoft.EntityFrameworkCore;

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    public BloggingContext(DbContextOptions<BloggingContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Configure Blog entity
        modelBuilder.Entity<Blog>()
            .HasKey(b => b.BlogId); // Specify primary key

        modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .IsRequired() // Make Url non-nullable
            .HasMaxLength(200); // Set max length

        // Configure Post entity and its relationships
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog) // One Post belongs to one Blog
            .WithMany(b => b.Posts) // One Blog can have many Posts
            .HasForeignKey(p => p.BlogId); // Specify foreign key property

        // More complex configurations can be done here...
    }
}

Common Model Configuration Scenarios

  • Primary Keys: Defining composite primary keys or custom key names.
  • Relationships: Configuring cascades, optionality, and defining join tables for many-to-many relationships.
  • Column Mappings: Specifying data types, nullability, length, and default values.
  • Owned Types: Configuring entities that do not have their own identity and are owned by another entity.
  • Complex Types: Mapping properties that are themselves complex objects.

EF Core provides a flexible and powerful way to model your data, allowing you to choose the configuration approach that best suits your project's needs, from simple convention-based setups to highly customized fluent API configurations.