niedziela, 29 sierpnia 2010

Model bazy danych i mapowania NHibernate

Po całym tygodniu szarpanego walczenia z NHibernate'm zdecydowałem się zrobić wstępny projekt bazy danych i odpowiednio go zmapować do wykorzystania w aplikacji. 


Model bazy 
Na początek zakładam nie dużą ilość informacji do przechowywania w bazie, dlatego też jej model nie może być bardzo skomplikowany. 
Graficzna reprezentacja modelu została stworzona w programie MySQL Workbench (nie wiem czy robiłem coś źle, czy też provider System.Data.SQLite nie działa jeszcze zbyt dobrze jeśli chodzi o tworzenie relacji pomiędzy tabelami, ale stworzone przeze mnie relacje nie chciały przenieść się w odpowiedni sposób do graficznego podglądu Data Setu).
Tą nieskomplikowaną strukturę tabel można streścić w prosty sposób:
  • Album - podstawowe informacje o albumie, czyli nazwa, data utworzenia, a także opcjonalnie opis oraz indeks zdjęcia będącego miniaturką
  • Photo - reprezentuje pojedyncze zdjęcie, zawiera ścieżkę bezwzględną do pliku ze zdjęciem, datę dodania oraz nieobowiązkowo opis i przyporządkowanie do jakiegoś albumu
  • Tag - tabela ze wszystkimi dostępnymi tagami
  • PhotoTag - odpowiada za przypisanie tagów do zdjęć
Większość pól jest oczywista i nie wymaga wyjaśnień. Zdecydowałem się na przechowywanie bezwzględnej ścieżki do zdjęcia i zapisanej w formacie bez dodatkowych znaków ucieczki.
Jeśli chodzi o relacje między tabelami to jeden album posiada wiele zdjęć (relacja 1:n), każde zdjęć może posiadać wiele tagów i jednocześnie każdy tak może być przyporządkowany do wielu zdjęć (relacja n:m) oraz każdy album ma jakąś miniaturkę w postaci zdjęcia (relacja 1:1, nie ujęta na diagramie). Co do ostatniej relacji mam pewne wątpliwości. Co w przypadku, gdy album nie zawiera żadnego zdjęcia (a relacja ta wymaga aby posiadał miniaturkę)? Ale ten problem odkładam na później, jeśli to faktycznie będzie problem to zmiana relacji nie powinna być kłopotliwa.


Mapowania NHibernate'a
Nie będę dokładnie opisywał każdego mapowania, pokażę całość dla tabeli Album i fragment dla pozostałych tabel (tabela PhotoTag nie wymaga jakiekolwiek mapowania, gdyż jest ona jedynie pośrednikiem w relacji n:m)
Najpierw stworzyłem klasę Album, która będzie reprezentowała w programie tablicę z bazy danych:
public class Album
{
  public virtual int AlbumId { get; set; }
  public virtual string Name { get; set; }
  public virtual string Description { get; set; }
  public virtual Photo Thumbnail { get; set; }
  public virtual DateTime Created { get; set; }
  public virtual Iesi.Collections.Generic.ISet Photos { get; set; }
}
Warto zauważyć, że do reprezentacji relacji jeden do wielu należy wykorzystać strukturę opartą na ISet<>, reprezentującą zestaw unikalnych (nie powtarzających się) obiektów. Niestety nie można skorzystać z wprowadzonej w C# 4.0 struktury ISet i w dalszym ciągu należy dołączać referencję do biblioteki Iesi.Collections (dostępnej zresztą w domyślnej instalacji NHibernate'a).
Następnie utworzyłem dokument XML mapujący klasę Album:

  
    
      
    
    
    
    
    
    
      
      
    
  

Najciekawszym fragmentem jest mapowanie relacji jeden do wielu. Pomimo początkowych wątpliwości okazało się, że taki zapis jest całkiem jasny i samowyjaśniający.
A mianowicie: tworzymy zestaw danych o nazwie Photos, pochodzący z tabeli Photo, który wykorzystuje typy generyczne i to elementy tego zestawu są odpowiedzialne za informację o relacji, poprzez posiadanie klucza o nazwie Album, a wszystkie elementy tego zestawu będą typu Photo
Po drugiej stronie relacji, w mapowaniu klasy Photo należy zawrzeć informację o tym do jakiego albumu należy zdjęcie. Załatwia to linijka:

Co również jest w miarę oczywiste. Wydaje mi się, że gdy stworzę jeszcze kilka takich mapowań, nie będę musiał więcej zaglądać do przykładów. 
Natomiast jeśli chodzi o mapowanie relacji wiele do wielu pomiędzy tabelami Photo oraz Tag wykorzystujemy worek (ang. bag), czyli strukturę zawierającą mogące się powtarzać obiekty. W klasie jest to odzwierciedlane poprzez strukturę opartą na IList. W pliku mapującym dodajemy znacznik:

  
  

Tłumaczenie tego kawałka jest następujące: struktura nieuporządkowana (bag) o nazwie Tags, działająca w oparciu o typy generyczne, wykorzystuje tablicę PhotoTag do stworzenia relacji wiele do wielu; w tej tablicy klasa Photo (której tyczy się to mapowanie) reprezentowana jest przez klucz obcy w kolumnie Photo, natomiast elementy z drugiego końca relacji odpowiadają kolumnie Tag i są klasy Tag.
Oczywiście dla klasy Tag mapowanie musi być symetryczne.


Do sprawdzenie działania tych relacji napisałem prosty data provider i kilka podstawowych testów, jednak nie podoba mi się jego postać oraz sposób zarządzania sesjami. Muszę trochę te sprawy przeorganizować. I jest znakomity temat na następnego posta.

Brak komentarzy:

Prześlij komentarz