0Pricing
C# Academy · Lekcja

Relacje: jeden-do-wielu i wiele-do-wielu

Modeluj i odpytuj relacje jeden-do-wielu oraz wiele-do-wielu za pomocą właściwości nawigacyjnych i Fluent API.

Relacje: jeden-do-wielu i wiele-do-wielu to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Relacje w EF Core

EF Core modeluje trzy typy relacji między encjami: jeden do jednego, jeden do wielu i wiele do wielu. Każdy typ wyraża się za pomocą właściwości nawigacyjnych i można go opcjonalnie skonfigurować za pomocą Fluent API.

Jeden do wielu: konfiguracja encji

Blog ma wiele elementów Posts. Encja zależna (Post) przechowuje klucz obcy. Właściwości nawigacyjne po obu stronach umożliwiają poruszanie się po relacji w obu kierunkach.

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public ICollection<Post> Posts { get; set; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public int BlogId { get; set; }        // FK
    public Blog Blog { get; set; } = null!; // nav property
}

Fluent API: relacja jeden do wielu

EF Core rozpoznaje relację na podstawie konwencji, ale można ją jawnie skonfigurować za pomocą Fluent API, aby zwiększyć czytelność i ustawić zachowanie podczas kaskadowego usuwania.

protected override void OnModelCreating(ModelBuilder mb)
{
    mb.Entity<Blog>()
      .HasMany(b => b.Posts)
      .WithOne(p => p.Blog)
      .HasForeignKey(p => p.BlogId)
      .OnDelete(DeleteBehavior.Cascade);
}

Wykonywanie zapytań za pomocą Include (ładowanie eager)

Należy użyć Include, aby załadować powiązane dane w ramach tego samego zapytania. Za pomocą ThenInclude można przejść głębiej w grafie nawigacji.

// Load blog with all its posts
var blog = await _db.Blogs
    .Include(b => b.Posts)
    .FirstOrDefaultAsync(b => b.Id == 1);

// Load posts with their comments too
var blogs = await _db.Blogs
    .Include(b => b.Posts)
        .ThenInclude(p => p.Comments)
    .ToListAsync();

Relacja wiele do wielu bez encji łączącej

EF Core 5+ obsługuje relacje wiele do wielu bez jawnej encji łączącej. Automatycznie tworzy tabelę łączącą na podstawie nazw typów encji.

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public ICollection<Course> Courses { get; set; } = new List<Course>();
}

public class Course
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public ICollection<Student> Students { get; set; } = new List<Student>();
}
// EF creates StudentCourse join table automatically

Relacja wiele do wielu z encją łączącą

Gdy tabela łącząca wymaga dodatkowych kolumn (np. daty zapisania i oceny), należy utworzyć jawną encję łączącą ze złożonym kluczem głównym.

public class Enrollment
{
    public int StudentId { get; set; }
    public Student Student { get; set; } = null!;
    public int CourseId { get; set; }
    public Course Course { get; set; } = null!;
    public DateTime EnrolledAt { get; set; }
    public decimal? Grade { get; set; }
}

// Fluent API config:
mb.Entity<Enrollment>().HasKey(e => new { e.StudentId, e.CourseId });
mb.Entity<Enrollment>().HasOne(e => e.Student).WithMany(s => s.Enrollments);
mb.Entity<Enrollment>().HasOne(e => e.Course).WithMany(c => c.Enrollments);

Wstawianie powiązanych danych

Należy dodać powiązane encje do kolekcji encji nadrzędnej przed wywołaniem SaveChangesAsync. EF Core automatycznie obsłuży wartości FK.

var blog = new Blog { Name = "Dev Notes" };
blog.Posts.Add(new Post { Title = "Hello EF Core" });
blog.Posts.Add(new Post { Title = "Migrations Deep Dive" });

_db.Blogs.Add(blog);
await _db.SaveChangesAsync();
// Inserts Blog + 2 Posts with correct BlogId FK

Filtrowanie powiązanych danych

W wyrażeniach LINQ można filtrować dane za pomocą właściwości nawigacyjnych. EF Core automatycznie tłumaczy takie zapytania na klauzule SQL JOIN.

// Blogs that have at least one published post
var popularBlogs = await _db.Blogs
    .Where(b => b.Posts.Any(p => p.IsPublished))
    .Select(b => new { b.Name, PostCount = b.Posts.Count(p => p.IsPublished) })
    .OrderByDescending(b => b.PostCount)
    .ToListAsync();

Kaskadowe usuwanie

W przypadku użycia DeleteBehavior.Cascade usunięcie encji głównej (Blog) automatycznie usuwa wszystkie encje zależne (Posts). Inne opcje to: SetNull, Restrict, NoAction.

// Delete a blog and all its posts
var blog = await _db.Blogs.FindAsync(1);
_db.Blogs.Remove(blog!);
await _db.SaveChangesAsync();
// Cascade: all Posts with BlogId=1 are also deleted

Typy encji należących jako obiekty wartościowe

Typy encji należących doskonale nadają się do modelowania obiektów wartościowych (np. Address). Są przechowywane w tej samej tabeli co encja właściciela i nie mają niezależnej tożsamości.

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public Address ShippingAddress { get; set; } = new();
}

public class Address
{
    public string Street { get; set; } = "";
    public string City { get; set; } = "";
    public string Country { get; set; } = "";
}

// Fluent API:
mb.Entity<Customer>().OwnsOne(c => c.ShippingAddress);

Praktyczny przykład: zamówienie z elementami

Kompletny wzorzec e-commerce: Order (encja główna) z wieloma OrderLines (encjami zależnymi), z których każda odwołuje się do Product.

var order = await _db.Orders
    .Include(o => o.Lines)
        .ThenInclude(l => l.Product)
    .FirstOrDefaultAsync(o => o.Id == orderId);

if (order is null) return Results.NotFound();

var summary = new
{
    OrderId = order.Id,
    Total   = order.Lines.Sum(l => l.Quantity * l.Product.Price),
    Items   = order.Lines.Select(l => new
    {
        l.Product.Name,
        l.Quantity,
        LineTotal = l.Quantity * l.Product.Price
    })
};
return Results.Ok(summary);

Szybkie sprawdzenie

Kiedy EF Core automatycznie tworzy tabelę łączącą bez jawnej encji łączącej?

Podsumowanie: relacje w EF Core

Najważniejsze informacje:

  • Relacja jeden do wielu: FK znajduje się w encji zależnej, właściwości nawigacyjne są po obu stronach; do ładowania należy użyć Include
  • Relacja wiele do wielu (prosta): dwie właściwości nawigacyjne ICollection — EF Core automatycznie tworzy tabelę łączącą
  • Relacja wiele do wielu (z danymi dodatkowymi): jawna encja łącząca ze złożonym kluczem PK
  • Kaskadowe usuwanie określa, co dzieje się z encjami zależnymi po usunięciu encji głównej
  • Encje należące służą do modelowania obiektów wartościowych w tej samej tabeli co encja właściciela

Często zadawane pytania

Czy lekcja „Relacje: jeden-do-wielu i wiele-do-wielu” jest bezpłatna?

Tak — pełny tekst „Relacje: jeden-do-wielu i wiele-do-wielu” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Relacje: jeden-do-wielu i wiele-do-wielu”?

Modeluj i odpytuj relacje jeden-do-wielu oraz wiele-do-wielu za pomocą właściwości nawigacyjnych i Fluent API. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Relacje: jeden-do-wielu i wiele-do-wielu”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy DbContext i DbSet
  2. Migracje i zarządzanie schematem
  3. Operacje CRUD z EF Core
  4. Relacje: jeden-do-wielu i wiele-do-wielu
← Powrót do C# Academy