ASP.NET

Entity Framework i podejście code-first w ASP.NET MVC – relacje

Prawie zapomniałem o napisaniu kontynuacji wpisu z zeszłego tygodnia, ale na szczęście temat, który chcę dzisiaj poruszyć nie jest zbyt skomplikowany. Chodzi o relacje między tabelami oraz ich odwzorowanie w kodzie – bo omawiamy przecież podejście code-first. Omówię dzisiaj trzy istniejące typy relacji: jeden do jednego, jeden do wielu oraz wiele do wielu. Zaczynajmy!

Zakładam oczywiście, że wiesz jak skonfigurować sobie Entity Framework i potrawisz uruchomić migrację aktualizującą bazę danych. Jeśli nie, zachęcam Cię do uprzedniego zapoznania się z moim artykułem:

Entity Framework i podejście code-first w ASP.NET MVC
– pierwsze kroki

Relacja jeden-do-jednego

Zakładam, że baza posiadać ma dwie tabele: Osoby i Adresy.

public class Osoba
{
    public int Id { get; set; }
    public string Imie { get; set; }
    public string Nazwisko { get; set; }
    public string Pesel { get; set; }
}

public class Adres
{
    public int Id { get; set; }
    public string Ulica { get; set; }
    public string Kod { get; set; }
    public string Miejscowosc { get; set; }
}

Relacja jeden do jednego nie jest raczej zbyt często spotykana. Tak czy inaczej warto się z nią zapoznać. Wyobraź sobie, że istnieją na świecie adresy, do których może być przypisana tylko jedna osoba, a każda z tych osób może posiadać przypisany tylko jeden adres. No więc?

Na start otwarcie bramek do klas, by widziały się wzajemnie (bramki – może mało profesjonalne, ale działa na wyobraźnię – otwieram sobie dostęp).

public class Osoba
{
    [Key]
    public int Id { get; set; }
    public string Imie { get; set; }
    public string Nazwisko { get; set; }
    public string Pesel { get; set; }

    public virtual Adres Adres { get; set; }
}

public class Adres
{
    [Key]
    public int Id { get; set; }
    public string Ulica { get; set; }
    public string Kod { get; set; }
    public string Miejscowosc { get; set; }

    public virtual Osoba Osoba { get; set; }
}

Jak wymusić teraz w tabeli Adresy powiązanie 1-1 do tabeli Osoby? Dodać klucz obcy Osoby do klucza głównego Adresy.

public class Adres
{
    [Key]
    [ForeignKey("Osoba")]
    public int Id { get; set; }
    public string Ulica { get; set; }
    public string Kod { get; set; }
    public string Miejscowosc { get; set; }

    public virtual Osoba Osoba { get; set; }
}

Sprawdzę teraz, co nam to dało. Szybki update bazy danych, wygenerowanie kodu SQL definicji bazy i oto efekt:

CREATE TABLE [dbo].[Adres] (
    [id]          INT            NOT NULL,
    [ulica]       NVARCHAR (MAX) NULL,
    [kod]         NVARCHAR (MAX) NULL,
    [miejscowosc] NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_dbo.Adres] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_dbo.Adres_dbo.Osobas_Id] FOREIGN KEY ([Id]) REFERENCES [dbo].[Osobas] ([Id])
);

Relacja jeden-do-wielu

Co jeśli jedna osoba posiada dwa adresy? A jeśli jeszcze więcej adresów?

Wystarczy mała modyfikacja klucza obcego (FK jako nowe pole) w tabeli Adresy, oraz zamiana bramki z jednorazową wartością na kolekcję wartości w tabeli Osoby.

[Table("Osoby")]
public class Osoba
{
    [Key]
    public int Id { get; set; }
    public string Imie { get; set; }
    public string Nazwisko { get; set; }
    public string Pesel { get; set; }

    public virtual ICollection<Adres> Adresy { get; set; }
}

[Table("Adresy")]
public class Adres
{
    [Key]
    public int Id { get; set; }
    public string Ulica { get; set; }
    public string Kod { get; set; }
    public string Miejscowosc { get; set; }

    [ForeignKey("Osoby")]
    public int OsobaId { get; set; }

    public virtual Osoba Osoby { get; set; }
}

Zmiana nazw tabel

Jak pewnie zauważyłeś, tabele otrzymują automatycznie wygenerowane nazwy. Możesz jednak przypisać im wybrane przez siebie nazewnictwo. Szerzej o adnotacjach będę pisał w kolejnym z tej serii artykule na blogu.

Generowanie definicji SQL

Po aktualizacji bazy, definicja SQL tabeli Adresy jest następująca:

CREATE TABLE [dbo].[Adresy] (
    [Id]          INT            IDENTITY (1, 1) NOT NULL,
    [Ulica]       NVARCHAR (MAX) NULL,
    [Kod]         NVARCHAR (MAX) NULL,
    [Miejscowosc] NVARCHAR (MAX) NULL,
    [OsobaId]     INT            NOT NULL,
    CONSTRAINT [PK_dbo.Adresy] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_dbo.Adresy_dbo.Osoby_OsobaId] FOREIGN KEY ([OsobaId]) REFERENCES [dbo].[Osoby] ([Id]) ON DELETE CASCADE
);

Relacja wiele-do-wielu

Usuwamy klucze obce, a bramki w obu tabelach otwieramy na kolekcje zamiast wartości pojedynczych. O resztę zadba EntityFramework.

[Table("Osoby")]
public class Osoba
{
    [Key]
    public int Id { get; set; }
    public string Imie { get; set; }
    public string Nazwisko { get; set; }
    public string Pesel { get; set; }

    public virtual ICollection<Adres> Adresy { get; set; }
}

[Table("Adresy")]
public class Adres
{
    [Key]
    public int Id { get; set; }
    public string Ulica { get; set; }
    public string Kod { get; set; }
    public string Miejscowosc { get; set; }
        
    public virtual ICollection<Osoba> Osoby { get; set; }
}

Jeśli odświeżysz eksplorator bazy danych, to zobaczysz automatycznie wygenerowaną tabelę mieszającą.

Automatycznie wygenerowana tabela haszująca
Automatycznie wygenerowana tabela mieszająca

Jej definicja jest następująca:

CREATE TABLE [dbo].[OsobaAdres] (
    [Osoba_Id] INT NOT NULL,
    [Adres_Id] INT NOT NULL,
    CONSTRAINT [PK_dbo.OsobaAdres] PRIMARY KEY CLUSTERED ([Osoba_Id] ASC, [Adres_Id] ASC),
    CONSTRAINT [FK_dbo.OsobaAdres_dbo.Osoby_Osoba_Id] FOREIGN KEY ([Osoba_Id]) REFERENCES [dbo].[Osoby] ([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_dbo.OsobaAdres_dbo.Adresy_Adres_Id] FOREIGN KEY ([Adres_Id]) REFERENCES [dbo].[Adresy] ([Id]) ON DELETE CASCADE
);
Pola tabeli haszującej
Pola tabeli mieszającej

Podsumowanie

Tyle na dzisiaj. Za tydzień we wtorek kolejny wpis z serii EntityFramework i podejście Code-First.

Poprzedni wpis z serii: Entity Framework i podejście code-first w ASP.NET MVC – pierwsze kroki

Tagi:asp.netcode-firstDaj Się Poznać 2017encjeentity frameworklogika aplikacji

Brak komentarzy

Napisz komentarz jako pierwszy!

Zostaw odpowiedź