Entity Framework Core Models

Understanding and defining your data models is fundamental to using Entity Framework Core (EF Core) effectively. EF Core uses Plain Old CLR Objects (POCOs) to represent your database schema. These POCOs are also known as entities.

Core Concepts

In EF Core, models are built using a combination of:

Defining Your Entities

You can define your entities simply by creating C# classes. EF Core can infer a lot about your model convention-based, but you can also use data annotations or the Fluent API to configure your model in detail.

Example: A Simple Blog Post Entity


namespace YourAppName.Models
{
    public class Post
    {
        public int Id { get; set; } // Primary Key (conventionally inferred)
        public string Title { get; set; }
        public string Content { get; set; }
        public DateTime PublishedDate { get; set; }

        // Navigation property to the author
        public int AuthorId { get; set; }
        public Author Author { get; set; }
    }

    public class Author
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }

        // Navigation property to the posts
        public ICollection<Post> Posts { get; set; }
    }
}
            

Configuring Your Model

Data Annotations

You can use attributes from the System.ComponentModel.DataAnnotations namespace to configure your model directly on your entity classes.


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

namespace YourAppName.Models
{
    public class Post
    {
        [Key] // Explicitly mark as Primary Key
        public int PostId { get; set; } // Property name doesn't need to be 'Id' if Key is specified

        [Required] // Makes the Title column NOT NULL
        [MaxLength(200)] // Sets the max length of the string column
        public string Title { get; set; }

        [Column("PostContent")] // Maps to a column named 'PostContent'
        public string Content { get; set; }

        public DateTime PublishedDate { get; set; }

        public int AuthorId { get; set; }
        public Author Author { get; set; }
    }
}
            

Fluent API

For more complex configurations or when you can't modify the entity classes, use the Fluent API within your DbContext.


using Microsoft.EntityFrameworkCore;

namespace YourAppName.Data
{
    public class AppDbContext : DbContext
    {
        public DbSet<Post> Posts { get; set; }
        public DbSet<Author> Authors { get; set; }

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

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Post>()
                .HasKey(p => p.PostId); // Explicitly set primary key

            modelBuilder.Entity<Post>()
                .Property(p => p.Title)
                .IsRequired()
                .HasMaxLength(200);

            modelBuilder.Entity<Post>()
                .Property(p => p.Content)
                .HasColumnName("PostContent"); // Map to 'PostContent' column

            modelBuilder.Entity<Post>()
                .HasOne(p => p.Author) // Define one-to-one or one-to-many relationship
                .WithMany(a => a.Posts)
                .HasForeignKey(p => p.AuthorId); // Define foreign key
        }
    }
}
            
Note: EF Core prioritizes the Fluent API over data annotations when there's a conflict.

Relationships

EF Core supports various relationships, including one-to-one, one-to-many, and many-to-many. These are typically defined using navigation properties and foreign keys.

One-to-Many Example

The Post and Author example above demonstrates a one-to-many relationship: one author can have many posts. The AuthorId in the Post entity acts as the foreign key.

Tip: Ensure your navigation properties are initialized (e.g., using ICollection<T> or by assigning an empty list in the constructor) to avoid null reference exceptions when accessing them.

Key Takeaways