NHibernate.Mapping.Attributes

NHibernate używa do mapowania modelu plików XML, Fluent NHibernate zamienił pliki XML na zwykły kod, NHibernate.Mapping.Attributes wprowadza kolejne udogodnienie – tworzenie mapowania za pomocą atrybutów już podczas definiowania modelu. Brzmi fajnie, zobaczmy jak to wygląda w praktyce…

Dokumentacja – gdzie ona jest?

Ogólnie dokumentacja do NHibernate mogłaby być lepsza, ale tutaj jest katastrofa…

Dokumentacja teoretycznie jest tutaj: http://www.nhforge.org/doc/nh/en/index.html#mapping-attributes

Niestety jest to tylko ogólny opis, w którym nie znajdziemy opisów poszczególnych atrybutów, nie znajdziemy tam nawet listy wszystkich atrybutów…

Jest tam odnośnik do przykładowego projektu, w którym mamy jeden ogromny plik z modelem i atrybutami do mapowania: DomainModel.cs (bagatela 1122 linie, 32kB). Po otwarciu nie wiedziałem czy się śmiać, czy płakać… Przyznam, że nie przejrzałem tego przykładu całego, ale nie rzucił mi się nigdzie w oczy opis atrybutów, ale na pewno dużo jest użytych i mają bardzo dużo parametrów (chociaż to samo widzę dzięki IntelliSense…)

Tworzymy aplikację

Prawdę mówiąc to jak zacząłem się tym bawić, to myślałem, że opiszę tylko jak zabrakło mi cierpliwości do rozgryzienia tego, ale po pewnym czasie spróbowałem ponownie i udało się zrobić przykład, którego używałem przy okazji innych wpisów, np. Entity Framework i PostgreSQL.

Zaczynamy standardowo od stworzenia aplikacji konsolowej:

  1. Otwórz Visual Studio
  2. Wybierz File -> New -> Project…
  3. Wybierz Console Application
  4. Nazwij projekt
  5. Wciśnij OK

i doinstalowania potrzebnych pakietów: Npgsql, NHibernate, NHibernate.Mapping.Attributes:

  1. Wybierz Tools -> Library Package Manager -> Manage NuGet Packages for Solution…
  2. Wyszukaj
  3. Zaznacz na liście znalezionych
  4. Wciśnij Install

Powtórz te kroki dla wszystkich potrzebnych pakietów.

Konfigurujemy aplikację i NHibernate

Do pliku app.config dodajemy w obrębie elementu configuration konfigurację xmlSerializera:

Defaultowo używa lokalizacji, gdzie użytkownik bez uprawnień administratora nie ma praw zapisu… Jest to potrzebne do działania tego narzędzia szczegóły dalej.

Tworzymy plik hibernate.cfg.xml z konfiguracją NHibernate:

Tworzymy model z atrybutami

Tworzymy klasy Author i Book:

Użyliśmy kilka atrybutów: Class, Id, Property, ManyToOne – banał 🙂

Zwróć tylko uwagę na parametr Name dla atrybutu Id, gdy nie miałem go zdefiniowanego nie byłem w stanie stworzyć poprawnego modelu…

Gdy mamy już zdefiniowaną bazę danych i jakimś cudem 😉 nazwy w bazie danych nie pasują do tych w modelu możemy użyć dodatkowych parametrów do poszczególnych atrybutów, np. Table, Column, ForeignKey,… Powodzenia 🙂

Sposób użycia

NHibernate.Mapping.Attributes generuje na podstawie modelu i atrybutów plik standardowy plik mapowania NHibernate w formacie hbm.xml. Dokładnie taki jaki ręcznie tworzyliśmy w tym przykładzie.

Dodaj do funkcji Main() w klasie Program poniższy kod:

Linie 1-2 to standardowe tworzenie konfiguracji NHibernate – używane dokładnie w ten sam sposób bez atrybutów.

Linia 3 wyświetla na konsolę wygenerowany plik hbm.xml – ta linia jest niepotrzebna z punktu widzenia działania programy, ale jest wygodna podczas nauki, dokładnie widać jak nasze atrybuty zostały przetworzone na mapowanie.

Linie 4-5 tworzą strumień zawierający mapowanie i dodają go do konfiguracji.

Teraz możemy juz stworzyć SessionFactory i wykonać przykładowe operacje na bazie:

Cały kod do pobrania tutaj.

Podsumowanie

Pierwszy akapit tego wpisu już sugerował, że nie przypadło mi to rozwiązanie do gustu – nic się od tego czasu nie zmieniło 🙂

Liczyłem na większe podobieństwo do Entity Framework, czyli model z atrybutami i korzystamy, ale tutaj dochodzi dodatkowy krok – tworzenie mapowania NHibernate, którego to używamy. Wiążą się z tym upierdliwe problemy, tzn. HbmSerializer dostarczany przez NHibernate.Mapping.Attributes tworzy jakieś mapowanie, które może ono być niepoprawne. W przypadku niepoprawnego mapowania NHibernate rzuca wyjątki, z których ciężko coś wywnioskować, bo przecież mapowanie zostało wygenerowane “pod stołem” i nie wiemy co tam się dzieje…

Zalecane w środowisku produkcyjnym jest generowanie plików hbm.xml i wczytywanie ich jak w “klasycznym” NHibernate – rozwiązuje to problem opisany wyżej, ale… po co nam te atrybuty skoro i tam musimy kombinować, żeby wygenerowały nam plik mapowania taki, jaki chcemy – łatwiej ręcznie napisać mapowanie.

W ekosystemie NHibernate najwygodniejszym rozwiązaniem wydaje mi się Fluent NHibernate, a NHibernate.Mapping.Attributes traktowałbym raczej jako ciekawostkę niż rozwiązanie produkcyjne.


Comments are closed.