entity-framework-relaciones-uno-a-muchos

One to Many Relationships in Entity Framework

  • 4 min

A one to many (1) relationship occurs when one entity A can have many instances of entity B, but each instance of B is related to only one A.

In other words, a record in one table can be related to multiple records in another table, but a record in the second table can only be associated with one record in the first table.

This is the most common type of relationship in databases

Let’s model a system where:

  • A Blog can have many Posts.
  • Each Post belongs to one Blog.
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    
    // Navigation property (1 → N)
    public ICollection<Post> Posts { get; set; } = new List<Post>();
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    
    // Implicit foreign key (BlogId)
    public int BlogId { get; set; }
    
    // Navigation property (N → 1)
    public Blog Blog { get; set; }
}

Configuring the relationship

With Naming Conventions

Entity Framework automatically infers the 1relationship if:

  • The “one” entity (Blog) has a collection of the “many” entity (ICollection<Post>).
  • The “many” entity (Post) has:
    • A navigation property pointing to the “one” (public Blog Blog).
    • A foreign key that follows the convention {ClassName}Id (BlogId).

With Data Annotations

If we do not follow the conventions, we can use attributes:

[ForeignKey] on the foreign key

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }

    [ForeignKey("Blog")] // Indicates that BlogId is FK of Blog
    public int BlogForeignKey { get; set; } // Non-conventional name

    public Blog Blog { get; set; }
}

[InverseProperty] for ambiguous relationships. Useful when there are multiple relationships between the same entities.

public class Blog
{
    public int BlogId { get; set; }
    
    [InverseProperty("Blog")] // Clarifies which property in Post corresponds
    public ICollection<Post> Posts { get; set; }
}

With Fluent API

In the DbContext, we use OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(b => b.Posts)       // A Blog has many Posts
        .WithOne(p => p.Blog)        // A Post belongs to a Blog
        .HasForeignKey(p => p.BlogId); // Foreign key in Post
}

Generated database structure

When applying a migration, EF creates the tables:

CREATE TABLE Blogs (
    BlogId INT PRIMARY KEY IDENTITY,
    Url NVARCHAR(MAX)
);

CREATE TABLE Posts (
    PostId INT PRIMARY KEY IDENTITY,
    Title NVARCHAR(MAX),
    Content NVARCHAR(MAX),
    BlogId INT NOT NULL,
    FOREIGN KEY (BlogId) REFERENCES Blogs(BlogId)
);

BlogId in Posts is a non-unique foreign key (allows multiple posts per blog).

Advanced configurations

Apart from basic relationships, Entity Framework allows advanced configuration of aspects of relationships between entities. This includes:

Relationship with cascade deletion

When a related entity is deleted, cascade deletion ensures that all related entities are also deleted.

modelBuilder.Entity<Book>()
    .HasOne(l => l.Author)
    .WithMany(a => a.Books)
    .OnDelete(DeleteBehavior.Cascade);

Read-only relationship

In some situations, you may not want to allow modification of a relationship in an entity.

modelBuilder.Entity<Book>()
    .HasOne(l => l.Author)
    .WithMany(a => a.Books)
    .OnDelete(DeleteBehavior.Restrict);

Optional relationships

Some relationships are optional, meaning that one entity may not have a relationship with the other.

modelBuilder.Entity<Book>()
    .HasOne(l => l.Author)
    .WithMany(a => a.Books)
    .IsRequired(false);  // Optional relationship

Practical examples