#csharp #dotnet #backend

Day 20: Relationships in EF Core

Welcome to Day 20. A database isn’t very useful with just one table. Real applications rely on relationships: An Author has many Books. A Student enrolls in many Courses.

EF Core handles these brilliantly using Navigation Properties.

One-to-Many Relationships

Let’s model the classic relationship: A Publisher can publish many Books. But a Book belongs to exactly one Publisher.

The Models

You define relationships using properties. If a Publisher has many Books, give them a List<Book>.

public class Publisher 
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    
    // Navigation Property: A publisher has a collection of books
    public List<Book> Books { get; set; } = new List<Book>(); 
}

public class Book 
{
    public int Id { get; set; }
    public string Title { get; set; } = string.Empty;
    
    // Foreign Key explicitly defined (Best Practice)
    public int PublisherId { get; set; }
    
    // Navigation Property: The actual Publisher object
    public Publisher? Publisher { get; set; } 
}

When you run dotnet ef migrations add AddPublishers, EF Core automatically sees these navigation properties and creates a Foreign Key column PublisherId on the Books table!

If you just run db.Publishers.ToList(), EF Core will not automatically fetch all their books! That would be a massive performance flaw if the database had millions of records.

Instead, you have to explicitly tell EF Core to grab the related books using .Include(). This is called Eager Loading, and it generates a SQL JOIN command.

using Microsoft.EntityFrameworkCore; // Required for .Include()

app.MapGet("/publishers", async (AppDbContext db) => 
{
    // Fetches publishers AND all their associated books!
    var publishers = await db.Publishers
        .Include(p => p.Books)
        .ToListAsync();
        
    return Results.Ok(publishers);
});

Warning: Be careful returning heavily nested objects directly from endpoints, as JSON serializers might crash due to infinite loop reference cycles (Publisher -> Book -> Publisher -> Book).

We fix these cycle issues tomorrow!

Challenge for Day 20

Create a new Author class. Update your Book class to have a One-to-Many relationship with Author. Generate the migration!

Tomorrow: Data Validation and DTOs to fix serializing cycles!