EF: Konwencje nazewnicze w podejściu Code First

Ten wpis jest odpowiedzią (na tyle na ile pozwala moja skromna wiedza) na komentarz do EF:Relacje między tabelami – Code First.  Dla porządku pozwoliłem sobie podzielić ów komentarz na części, na które będę bezpośrednio odpowiadał. Zaczynajmy 🙂

mógłbyś mi wyjaśnić parę rzeczy z EntityFramework i podejścia CodeFirst w C#?. Jak to wygląda z relacjami?? z tego co w netach czytałem to jeśli chcę jeden-do-jednego to robię w tabeli coś w stylu

public class Player
{
public int Id {get; set; } // tutaj niby już automatycznie ustawia jako klucz główny tabeli, inny sposób co widziałem to podanie tej właściwości z inną nazwą i dodanie atrybutu nad nim [Key] ??

public string Nick { get; set;}
public virtual Guild Guild { get; set; }

// coś tam dalej
}

public class Guild
{
public int Id { get; set; }
public string Name { get; set;}

public virtual ICollection Players { get; set; }

public Guild()
{
this.Players = new HashSet();
}
}

I u góry podana nazwa właściwości relacji identycznie co nazwa klasy ‘public virtual Employer Employer {get; set;}’ i tutaj pytanie czy zawsze tak musi być?? (w sumie mógłbym sam sprawdzić, ale wolę dopytać kogoś ogarniętego w temacie).

Pierwsza kwestia (to pewnie przeoczenie): przykład który podałeś nie obrazuje relacji jeden-do-jednego a jeden-do-wielu. Guild może “posiadać” wielu Player’ów, ale Player może być przypisany tylko do jednego Guild’a.  Gdybyśmy chcieli żeby była to relacja jeden-do-jeden kod mógłby wyglądać tak:

Tak jak napisałeś, właściwość Id w klasie Player, automatycznie zostanie zinterpretowana jak klucz główny w bazie. Podobnie stałoby się gdyby ta właściwość nazywała się PlayerId. EF kojarzy te dwie konwencje: Id, lub NazwaKlasyId. W przypadku gdybyś chciał aby nosił on inną nazwę, musiałbyś (tak jak napisałeś w komentarzu) oznaczyć właściwość atrybutem Key.

Jeżeli chodzi o nazwę, jak ją określiłeś, właściwości relacji – w powyższym przykładzie będzie to linijka:

Istotne jest tylko że jest to właściwość publiczna i określonego typu. Nazwa nie jest istotna po za tym, że implikuje jak będzie nazywał się klucz obcy prowadzący do tabeli Guild – w momencie gdy sami go nie określimy, co zrobiłem za pomocą atrybutu ForeignKey – z tabeli Player. Łatwo to można zaobserwować w relacji jeden do wielu EF: na podstawie nazwy tej właściwości generuje nazwę klucza obcego, dodając podkreślnik i człon Id. Czyli np. w tabeli Player znalazłaby się kolumna Guild_Id. Gdyby linijka określająca relację wyglądała tak:

to kolumna nazywałaby się PlayerGuild_Id.

Podobnie wygląda przy relacji jeden do wielu. I nie wiem czy tutaj taki wymóg, gdzie później to rozpoznaje jako relację, że podaje się liczbę mnogą do klasy, z angielskiego to pewnie z automatu typu Player to Players, Guild i Guilds. A jak nazwy będą Polskie?? np. Gracz to jak wpiszę Gracze to będzie ok?? jak to wygląda z tymi nazwami poprawnymi, żeby widziało jako normalne relacje.

Takiego wymogu nie ma. Co więcej możesz nazwać tą właściwość w dowolny sposób. W tym wypadku Entity Framework skorzysta z konwencji i utworzy w drugiej klasie nazwę klucza obcego jako NazwaKlasyId. Relacja zawsze będzie tu widoczna na podstawie tego że właściwość ma określony typ i jest publiczna. Także tu nie masz się o co martwić, natomiast moim zdaniem, nazywanie tej właściwości za pomocą nazwy klasy w liczbie mnogiej to dobra praktyka ponieważ w jasny sposób określa co się tam znajduje. W tym wypadku kolekcja instancji klasy Player. Po za tym jest to dosyć szeroko znana konwencja, więc przeglądając kod innych osób często się na nią natkniesz.

Kolejne pytanie to jak to z odczytaniem wygląda żeby od razu mi odczytało całe relacje bez Lazy-loading czy jak to tam się zwało, że zaczytywało by z czasem. Dawniej coś z tym kombinowałem no i używałem Include np. w taki sposób:

var guilds = context.Guilds
.Include(“Players”)
.ToList();

Tylko pytanie czy w taki sposób poprawnie się pobiera dane jeśli relacje utworzone?

Zasadniczo Twój kod spełnia to czego wymagasz (o ile się dobrze rozumiemy). Możesz też wyłączyć lazy loading dla poszczególnych klas pomijając słowo kluczowe virtual przy właściwości określającej relację, lub dla wszystkich klas ustawiając w swoim DbContext’cie właściwość Configuration.LazyLoadingEnabled na false (Configuration to składowa klasy DbContext po której dziedziczysz swój kontekst).

No i ostatnie pytanie czy jest jakaś różnica przy nazwach tych DbSetów w klasie DbContextu np

public DbSet Gracze {get; set;}

czy tutaj jest jakaś różnica w tym czy nazwę Gracze czy też GraczeWypasni itd.??

Nazwy DbSetów, nie mają znaczenia dla Entity Framework’a, mają za to dla programisty więc po prostu dbajmy by były czytelne i zrozumiałe. 🙂


Mam nadzieję, że udało mi się pomóc. W razie jeszcze jakichś pytań zachęcam do kontaktu.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *