.NET Data Access

Microsoft Learn | Documentation

Entity Framework Models

Understanding and defining models is a foundational step when working with the Entity Framework (EF). EF models represent your application's data structures and their relationships. These models are typically defined using C# or VB.NET classes, which map directly to your database tables or other data stores.

Core Concepts of EF Models

Entity Framework primarily uses Plain Old CLR Objects (POCOs) to represent entities. These classes define the properties that correspond to the columns in your database tables.

  • Entities: These are POCO classes that represent objects in your domain (e.g., Customer, Product, Order).
  • Properties: Each property in an entity class typically maps to a column in a database table. EF infers these mappings based on naming conventions or explicit configuration.
  • Relationships: EF supports common relational database concepts like one-to-one, one-to-many, and many-to-many relationships between entities. These are modeled using navigation properties.
  • DbContext: The DbContext is the primary class for interacting with the EF data provider. It represents a session with the database and can be used to query and save data.

Defining Models

You can define your EF models in two primary ways:

  1. Code First: You write your entity classes first, and EF generates the database schema based on your code. This is a popular approach for new projects or when you want to start with a clean domain model.
  2. Database First: You can scaffold your entity classes from an existing database. EF will generate the POCO classes and the DbContext based on your database schema. This is useful for integrating with legacy databases.

Example: A Simple Customer Entity (Code First)


public class Customer
{
    public int CustomerId { get; set; } // Primary Key
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }

    // Navigation Property for Orders (One-to-Many relationship)
    public virtual ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int OrderId { get; set; } // Primary Key
    public DateTime OrderDate { get; set; }
    public decimal TotalAmount { get; set; }

    // Foreign Key property
    public int CustomerId { get; set; }

    // Navigation Property to the related Customer
    public virtual Customer Customer { get; set; }
}
                

Model Configuration

While EF has conventions for mapping, you often need to configure your models more explicitly. This can include specifying primary keys, foreign keys, relationships, table names, column names, data types, and constraints. This is typically done using the OnModelCreating method in your DbContext class, often leveraging the Fluent API.

Example: Fluent API Configuration


using Microsoft.EntityFrameworkCore;

public class MyDbContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Order> Orders { get; set; }

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Configure Customer entity
        modelBuilder.Entity<Customer>().HasKey(c => c.CustomerId);
        modelBuilder.Entity<Customer>().Property(c => c.FirstName).IsRequired().HasMaxLength(100);
        modelBuilder.Entity<Customer>().Property(c => c.LastName).IsRequired().HasMaxLength(100);
        modelBuilder.Entity<Customer>().Property(c => c.Email).HasMaxLength(255);

        // Configure Order entity
        modelBuilder.Entity<Order>().HasKey(o => o.OrderId);
        modelBuilder.Entity<Order>().Property(o => o.OrderDate).IsRequired();
        modelBuilder.Entity<Order>().Property(o => o.TotalAmount).HasColumnType("decimal(18, 2)").IsRequired();

        // Configure the relationship between Customer and Order
        modelBuilder.Entity<Customer>()
            .HasMany(c => c.Orders)
            .WithOne(o => o.Customer)
            .HasForeignKey(o => o.CustomerId);
    }
}
                
Important: When using Code First, ensure your entity classes are designed to be "plain" and do not contain EF-specific attributes unless you intend to use the Data Annotations approach for configuration. The Fluent API within OnModelCreating provides a more flexible and maintainable way to configure your model.

Key Takeaways

  • Models are the bridge between your .NET code and your data store.
  • Use POCO classes to represent your entities.
  • Understand the Code First and Database First approaches.
  • Leverage the Fluent API for robust model configuration.

Continue to the next section to learn about querying data with Entity Framework.