niedziela, 29 września 2013

nHibernate " is not mapped"

Wyjątek z tematu "[Class] is not mapped" jest jednym z częściej występujących błędów podczas pracy z nHibernate. Związane jest to głównie z tym, że większość pracy wykonujemy manualnie wprowadzając nazwy klas i mapowań jako zwykłe ciągi znaków (string) co przekłada się na ilość błędów.

Przyczyn tego wyjątku można szukać w kilku miejscach. Miejsca w których można popełnić błędy podzieliłem na 4 obszary:
  1. App/web config
  2. Plik mapowania klasy na tabelę w bazie
  3. Tworzenie sesji
  4. Zapytania


1. App/web .config
W pliku tym ustawiamy podstawowe właściwości fabryki sesji. Jednym z ważniejszych parametrów jest ten, mówiący gdzie znajdują się mapowania klas do tabel:


Code:
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
    <session-factory>
      <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.connection_string">Server=localhost;initial catalog=AdventureWorksLT2012;Integrated Security=True</property>
      <mapping assembly="nHibernateCreatingMapping" />
    </session-factory>
  </hibernate-configuration>

Po wystąpieniu tego błędu sprawdzamy więc w/w plik i szukamy czy znajduje się tam linijka mówiąca w którym assembly znajdują się mapowania.


2. Plik mapowania klasy na tabelę w bazie
W tym pliku można popełnić szereg błędów:


Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="nHibernateCreatingMapping" namespace="nHibernateCreatingMapping.Domain">
  <class name="ProductDescription" table="SalesLT.ProductDescription">

Rzeczy które sprawdzamy:
  • czy nazwa assembly jest na pewno poprawna
  • czy namespace się zgadza
  • czy w nazwie klasy nie popełniliśmy błędu
  • czy we właściwościach pliku zaznaczyliśmy Build Action na Embedded Resource
Jak widać możliwość popełnienia 4 błędów - całkiem sporo.


3. Tworzenie sesji:


Code:
            ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
            var session = sessionFactory.OpenSession();

Tutaj także można popełnić niewinny błąd i przez pośpiech możemy zapomnieć o wywołaniu metody Configure przed stworzeniem obiektu fabryki sesji.


4. Zapytania
Jeżeli do tworzenia zapytań wykorzystujemy HQL, należy pamiętać że w zapytaniach używamy nazwy klasy a nie tak jak by się mogło wydawać - tabeli.


Code:
var productDescriptions = session.CreateQuery("from ProductDescription").List<ProductDescription>();



Wiele osób porzuca nHibernate z powodu problemów konfiguracyjnych. Po kilku dniach używania biblioteki można w łatwy sposób identyfikować miejsca gdzie potencjalnie popełniliśmy błąd. Aby ułatwić sobie pracę i przy okazji używać silnie typowanych danych można skorzystać z fluent nHibernate - ale o tym w osobnym poście.

3 komentarze:

  1. Miło słyszeć, że NHibernate nie wymiera i zaczynasz się w niego zagłębiać - będę na pewno śledził Twoje przygody.

    Do zapytań polecam korzystać z QueryOver:

    var productDescriptions = session.QueryOver().List();

    W takim wypadku dużo trudniej o błąd w stringu.
    Warto od razu wspomnieć jak np. filtrować i sortować:

    var productDescriptions = session.QueryOver().Where(k=>k.ModifiedDatek.Description).Asc.List();

    Dzięki takim mechanizmom kompilator dba o to, żebyśmy nie popełniali głupich błędów, a pisanie takich prostych zapytań to czysta przyjemność.

    OdpowiedzUsuń
  2. ...Coś w poprzednim komentarzu powycinało mi kawałki kodu.
    Jak tutaj wstawić poprawnie fragment tekstu w nawiasach trójkątnych?...

    OdpowiedzUsuń
    Odpowiedzi
    1. Nie wiem w jaki sposób to wklejać, żeby się dobrze formatowało. W wolnej chwili poszukam w ustawieniach.

      Usuń