niedziela, 1 kwietnia 2012

Relacje w EntityFramework Code First Fluent API

Tym razem bardziej "ćwiczebnie", czyli o definiowaniu relacji w EF code first, przy użyciu Fluent API.
Często się zdarza iż są z tym problemy, w tym artykule przedstawię mini ściągę jak sobie z tym problemem radzić - na kilku przykładach.

Przykłady transformacji zostały zaczerpnięte ze strony http://wazniak.mimuw.edu.pl (kurs baz danych)

1. Relacja 1:1:


Kod C#:

    public class Pracownik
    {
        public int IdPracownika { get; set; }
        public string Nazwisko { get; set; }
        public string Etat { get; set; }
        public decimal Pensja { get; set; }
    }

    public class Samochod
    {
        public string NrRejestracyjny { get; set; }
        public string Marka { get; set; }
        public string Model { get; set; }
        public int IdPracownika { get; set; }
        public Pracownik Pracownik { get; set; }
    }

    class TestContext : DbContext
    {
        public DbSet Pracownicy { get; set; }
        public DbSet Samochody { get; set; }

        public TestContext(string connectionString) : base(connectionString)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity().HasKey(x => x.IdPracownika);
            modelBuilder.Entity().HasKey(x => x.NrRejestracyjny);
            modelBuilder.Entity().Property(x => x.NrRejestracyjny).HasMaxLength(10);

            modelBuilder.Entity().HasRequired(x => x.Pracownik).WithMany().HasForeignKey(x => x.IdPracownika);
        }
    }

Wynik uruchomienia i powstałe struktury w bazie:




2. Relacja 1:M:


Kod C#:

    public class Pracownik
    {
        public int IdPracownika { get; set; }
        public string Nazwisko { get; set; }
        public string Etat { get; set; }
        public decimal Pensja { get; set; }
        public Dzial Dzial { get; set; }
        public int IdDzial { get; set; }
    }

    public class Dzial
    {
        public int IdDzial { get; set; }
        public string Nazwa { get; set; }
        public string Siedziba { get; set; }
        public IList Pracownicy { get; set; }
    }

    class TestContext : DbContext
    {
        public DbSet Pracownicy { get; set; }
        public DbSet Dzialy { get; set; }

        public TestContext(string connectionString) : base(connectionString)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity().HasKey(x => x.IdDzial);
            modelBuilder.Entity().HasKey(x => x.IdPracownika);

            modelBuilder.Entity().HasRequired(x => x.Dzial).WithMany(x => x.Pracownicy).HasForeignKey(x => x.IdDzial);
        }
    }
1
W bazie będzie się przedstawiać w następujący sposób:



3. Relacja typu M:N:


W tym przypadku EF CF bardzo dobrze generuje schemat już z samego kodu, a mianowicie:

    public class Pracownik
    {
        public int IdPracownika { get; set; }
        public string Nazwisko { get; set; }
        public string Etat { get; set; }
        public decimal Pensja { get; set; }
        public virtual IList Projekty { get; set; } 
    }

    public class Projekt
    {
        public int NrProjektu { get; set; }
        public string Nazwa { get; set; }
        public string Sponsor { get; set; }
        public virtual IList Pracownicy { get; set; }
    }

Takie rozwiązanie jest dobre jednak ma jedną wadę - zawsze lepiej mieć tabelę pośrednią zdefiniowaną w kodzie. Ułatwia to późniejsze konstruowanie zapytań. Dlatego skorzystamy i tutaj z Fluent Api:

    public class Pracownik
    {
        public int IdPracownika { get; set; }
        public string Nazwisko { get; set; }
        public string Etat { get; set; }
        public decimal Pensja { get; set; }
        public int IdProjekt { get; set; }
    }

    public class Projekt
    {
        public int NrProjektu { get; set; }
        public string Nazwa { get; set; }
        public string Sponsor { get; set; }
        public int IdPracownik { get; set; }
    }

    public class PracownicyProjekty
    {
        public int IdPracownik { get; set; }
        public int IdProjekt { get; set; }

        public Pracownik Pracownik { get; set; }
        public Projekt Projekt { get; set; }
    }

    class TestContext : DbContext
    {
        public DbSet Pracownicy { get; set; }
        public DbSet Projekty { get; set; }
        public DbSet PracownicyProjekty { get; set; }

        public TestContext(string connectionString) : base(connectionString)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity().HasKey(x => x.NrProjektu);
            modelBuilder.Entity().HasKey(x => x.IdPracownika);
            modelBuilder.Entity().HasKey(x => new { x.IdPracownik, x.IdProjekt });
            modelBuilder.Entity().HasRequired(x => x.Pracownik).WithMany().HasForeignKey(x => x.IdPracownik).WillCascadeOnDelete(false);
            modelBuilder.Entity().HasRequired(x => x.Projekt).WithMany().HasForeignKey(x => x.IdProjekt);
        }
    }

Oczywiście jest to propozycja, która może ułatwić w przyszłości pisanie zapytań LINQ.

Brak komentarzy:

Prześlij komentarz