sobota, 1 grudnia 2012

[SQL|ORM] Entity Framework : Database First

Database First to podejście, w którym mamy już stworzoną bazę danych i chcemy ją jedynie zmapować na encje w naszej aplikacji. Przy takiej okazji pojawia się kilka ciekawych zagadnień.

Modelowanie relacji wiele do wielu

W relacyjnych bazach danych do tworzenia tego typu relacji stosuje się tzw. junction tables. Są to tabele, które zawierają przeważnie dwie kolumny - klucze obce do obu "stron" relacji. Prosty skrypt tworzący taką relację poniżej

CREATE TABLE Album (
  AlbumId INT IDENTITY PRIMARY KEY,
  AlbumName VARCHAR(50)
  )
 
CREATE TABLE Artist (
  ArtistId INT IDENTITY PRIMARY KEY,
  FirstName VARCHAR(50),
  MiddleName VARCHAR(50),
  SecondName VARCHAR(50)
  )
 
CREATE TABLE LinkTable (
  ArtistId INT NOT NULL ,
  AlbumId INT NOT NULL ,
  PRIMARY KEY (ArtistId, AlbumId) ,
  CONSTRAINT fk_Artist_has_Album
    FOREIGN KEY (ArtistId)
    REFERENCES Album (AlbumId),
  CONSTRAINT fk_Album_has_Artist
    FOREIGN KEY (AlbumId)
    REFERENCES Artist (ArtistId)
    );

Po dodaniu ADO .NET Entity Data Model i wybraniu powyższych tabel, otrzymamy w designerze dwie encje połączone relacją wiele do wielu.

Obie encje otrzymały dodatkowe Navigation Properties mapowane do LinkTable. Dzięki temu w łatwy sposób można dodawać Artystów do albumu (i na odwrót) przez dodanie referencji do kolekcji.

Nieco inaczej sytuacja wygląda w przypadku, gdy tabela łącząca zawiera dodatkowe dane.Wtedy Entity Framework utworzy trzy encje danych, jak w przykładzie poniżej:
Dane dodajemy zatem do tabel poprzez stworzenie trzech obiektów.

Modelowanie tabel zawierających referencje do samych siebie

Tabele zawierające klucz główny, oraz klucz obcy będący referencją do własnego klucza głównego są w relacji do samych siebie. Dodając taką tabelę do EDM dostaniemy encję z dwoma dodatkowymi Navigation Properties. Możemy zmienić ich nazwy, na takie, które będą odpowiadały ich reprezentacji. Jedna z nich będzie właściwością skalarną (relacja 0..1), drugą kolekcją (relacja 1..*). W ten sposób modelowane mogą być dane reprezentowane np. jako drzewa.

Encja taka może mieć jedną nadkategorię (lub nie mieć nadkategorii - relacja 0..1) oraz wiele podkategorii.

Jedna encja - wiele tabel

Mamy dwie tabele dzielące ten sam klucz główny. Z punktu widzenia programu możemy połączyć zatem dwie encje w jedną.



Po wybraniu obu tabel w okienku Entity Data Model, dostaniemy dwie encje w designerze. Aby je połączyć, należy:
  • Przekopiować właściwości z encji ProductWebInfo do Product
  • Usunąć ProductWebInfo, wybierając opcję No przy pytaniu o usuwanie tabel z store model
  • W widoku Mapping Details w VS dla encji Product należy dodać tabelę ProductWebInfo
  • Dla tabeli ProductWebInfo ustawić mapowania (SKU na property SKU, ImageURL na property ImageURL)
Podczas zapisywania obiektu encji Product do bazy danych zostaną dodane wpisy do obu tabel.

Jedna tabela - wiele encji

Sytuacja taka może być przydatna, gdy mamy w tabeli pewne pola dużych rozmiarów, z których rzadko korzystamy. Aby nie ładować ich nie potrzebnie za każdym razem możemy dodać tabelę do EDM, a następnie odpowiednio zmapować ją do dwóch encji:
  • Dodać nową encję do designera, zmieniając w polu klucza wartość na nazwę kolumny klucza głównego  z encji głównej
  • Przenieść rzadko używane właściwości do nowej encji
  • W Mapping Window na nowej encji dodać tabelę i ustawić mapowanie właściwości na odpowiednie kolumny
  • Dodać asocjację (PPM na jednej z encji) między dwoma encjami, ustawioną na 1 do 1, odznaczając dodawanie nowego klucza obcego
  • Ostatecznie klikając dwukrotnie na połączeniu należy dodać ograniczenia (Constraint) w Referential Constraint ustawiając Principal na Photograph, a właściwości klucza na PhotoId
Po poprawnej konfiguracji otrzymujemy Lazy Loading dla pól w dodatkowej encji. Warto pamiętać, że usuwając encję główną, usuwane także encję dodatkową, oraz, że aby dodać encję dodatkową do zbioru, musi istnieć odpowiadająca jej encja główna.

Modelowanie dziedziczenia "tabela per typ"

Dysponujemy jedną tabelą główną, oraz dwoma powiązanymi z nią relacjami kluczy obcych. Dwie dodatkowe tabele stanowią uzupełnienie informacji o obiekcie z tabeli głównej.



Z punktu widzenia aplikacji pisanej w języku obiektowym, dwie tabele dziedziczą z tabeli głównej. Aby zamodelować dziedziczenie w EF, należy po dodaniu trzech tabel do Entity Data Model:
  • usunąć wszystkie asocjacje
  • na encji odpowiadającej tabeli głównej wybrać Add...Inheritance. W dialog boxie wybrać tabelę bazową jako encję bazową oraz jedną z tabel uzupełniających, jako encję dziedziczącą
  • czynność powtórzyć dla drugiej tabeli
  • w oknie mapowania usunąć property odpowiadające kolumnie z kluczem obcym z encji dziedziczących i dodać je, jako mapowane do kolumny z tabeli głównej
W efekcie uzyskamy hierarchę obiektów jak poniżej:


Filtrowanie kolekcji obiektów

Podczas mapowania tabeli na encję możemy założyć filtr odrzucający pewne rekordy. Przykładowo możemy odrzucać wszystkie wpisy, gdzie pola z pewnej kolumny są różne od NULL. Po dodaniu tabeli do EDM, należy przejść do widoku Mapping Details, a następnie kliknąć w opcję <Add a Condition> . W dodanym warunku wybieramy kolumnę, rodzaj warunku (is lub =) i wartość (w tym przypadku is Null. Nie będziemy potrzebowali więcej property, które służy za warunek, zatem można je usunąć z listy właściwości na encji. Pozostałe możliwości warunków
  • <column> Not Null
  • <integer> = <value>
  • <String> = <value>

Modelowanie dziedziczenia "tabela per hierarchia"

Mamy tabelę, zawierającą jedną kolumnę, która determinuje typ (rodzaj) obiektu. Chcemy tak zmapować ją do encji, aby uzyskać jeden bazowy typ abstrakcyjny i dwa dziedziczące z niego. Po dodaniu naszej tabeli do Entity Data Model należy:
  • Dodać dwie dodatkowe encje w designerze, które będą reprezentowały typy dziedziczące. Podczas dodawania należy ustalić typ bazowy na encję mapowaną bezpośrednio do tabeli
  • Przenieść properties charakterystyczne dla danego typu z encji bazowych do odpowiednich encji dziedziczących
  • W widoku Mapping Details wybrać dla obu typów dziedziczących tabelę, do której będą mapowane, oraz sprawdzić poprawność mapowania properies nowej encji do odpowiednich kolumn tabeli
  • W tym samym widoku w polu Add a Condition należy dodać warunek na podstawie kolumny z tabeli głównej, np. 


W opcjach encji bazowej można ustawić pole abstract na true, oraz usunąć property decydujące o typie encji.



Modelowanie relacji typu "Is-a" oraz "Has-a"

Może się zdarzyć taka sytuacja że dwie tabele są w relacji przedstawionej poniżej:


Obie tabele posiadają ten sam klucz główny, a dodatkowo jedna posiada asocjację z drugą poprzez klucz obcy.

Aby uprościć dostęp do danych po stronie programu, możemy dodać je do EDM, a następnie:
  • usunąć asocjację 1...0.1
  • na tabeli bez klucza obcego dodać Inheritance i jako encję dziedziczącą dodać tą odpowiadającą drugiej tabeli
  • z encji dziedziczącej usunąć property odpowiadające kluczowi głównemu, a w szczegółach mapowania ustawić mapowanie tej kolumny (ParkId) na Id encji bazowej (LocationId)
  • zmienić nazwę Navigation Property reprezentującego klucz obcy
Uproszone encje wyglądają następująco:


Typy złożone

Jedna tabele reprezentuje kilka logicznych obiektów, np osobę i jej adres jednocześnie.

Po dodaniu do EDM tabeli, należy:
  • zaznaczyć properties z danej grupy i kliknąć opcję Refactor into New Complex Type dostępną pod prawym przyciskiem myszy
  • w widoku Model Browser możemy zmienić typ np. na Name oraz w Designerze możemy zmienić nazwę property
  • Complex property można także dodawać poprzez kliknięcie prawym przyciskiem myszy na encji i wybranie Add...ComplexProperty. 
  • W oknie szczegółów mapowania wszystkie properties powinny być mapowane na propercje typów złóżonych


Brak komentarzy:

Prześlij komentarz