Na początek może dwa zdania co to takiego jest O/R Mapping. Jak podaje wikipedia jest to technika programistyczna do konwersji niekompatybilnych typów systemowych z postaci relacyjnej na obiektową. Jest to prawda, ponieważ relacyjne bazy danych operują na tabelach, obiektowe języki na obiektach. Istnieje wiele różnych komercyjnych jak i niekomercyjnych rozwiązań ORM, niezaprzeczalnie jednym z najbardziej popularnych jest NHibernate. NHibernate wiele zawdzięcza swojemu starszemu bratu z platformy Java o nazwie Hibernate – skądś to znamy ;).
Po takim krótkim wstępie chciałbym jednak oznajmić, iż celem artykułu nie jest opis samego NHibernate-a. Kieruje się tu do osób, które mają już pewne doświadczenie w pracy z NHibernate. Moim zadaniem tutaj będzie pokazanie jak Spring.NET integruje się z NHibernate.
provider=”SqlServer-1.1″
connectionString=„Data Source=BENIAMINZ\SQLEXPRESS;Initial Catalog=ADMINET;Integrated Security=SSPI;”/>
<property name=”DbProvider” ref=”DbProvider”/>
<property name=”MappingAssemblies”>
<list>
<value>BizDev.SampleSpring.Model</value>
</list>
</property>
<property name=”HibernateProperties”>
<dictionary>
value=”NHibernate.Connection.DriverConnectionProvider”/>
value=”NHibernate.Dialect.MsSql2005Dialect”/>
value=”NHibernate.Driver.SqlClientDriver”/>
</property>
Jak widać nasz SessionFactory bazuje na odpowiednim DbProvider o którym była mowa w poprzedniej części. DbProvider dostarcza nam tu informacji potrzebnych do nawiązania połączenia z bazą danych. W następnej kolejności określamy assembly w którym znajdują się pliki mapowania NHibernate-a. Sekcja HibernateProperties zawiera standardowe parametry konfiguracyjne NHibernate-a. Tutaj określiłem dialekt oraz driver bazy danych.
Przejdziemy teraz do wywołania właściwego kodu. NHibernate zawiera co najmniej trzy sposoby na wykonanie operacji na naszych zmapowanych obiektach. Pierwsze podejście opiera się na HibernateTemplate. To klasa narzędziowa pozwalająca na wywołanie standardowych metod CRUD sesji NHibernate. Spójrzmy na przykład:
public class AbonentDAO : IAbonentDAO { private HibernateTemplate hibernateTemplate; ISessionFactory SessionFactory { set { hibernateTemplate = new HibernateTemplate(value); } } public void Zapisz(Abonent abonent) { hibernateTemplate.SaveOrUpdate(abonent); } } |
Widzimy prosty obiekt typu Data Access Object dla uproszczenia zawierający tylko metodę Zapisz. Wewnątrz metody jest wywoływane standardowe SaveOrUpdate z sesji NHibernate.
Jedyne co musimy dostarczyć to SessionFactory – oczywiście możemy to zadanie zlecić kontenerowi IoC. Fragment pliku konfiguracyjnego, który pozwoli wstrzyknąć instancję zdefiniowanego wcześniej SessionFactory do naszego DAO, wygląda tak:
<property name=”SessionFactory” ref=”MySessionFactory”/>
</object>
public Abonent PobierzAbonenta(Guid idAbonenta) { return nhibernateTemplate.Execute( delegate(ISession session) { return session.CreateQuery(”from Abonent a where a.Id = : idAbonenta”) .SetGuid(”idAbonenta’, idAbonenta’) .UniqueResult<Abonent>(); } ); } |
public class AbonentDAO : HibernateDaoSupport, IAbonentDAO { public void Zapisz(Abonent abonent) { ISession session = DoGetSession(false); session.SaveOrUpdate(abonent); } } |
public class AbonentDAO : IAbonentDAO { private ISessionFactory sessionFactory; public ISessionFactory SessionFactory { get { return sessionFactory; } set { sessionFactory = value; } } public void Zapisz(Abonent abonent) { SessionFactory.GetCurrentSession().SaveOrUpdate(abonent); } } |
Jedyne co nam pozostaje to tylko wstrzyknięcie referencji do zdefiniowanego wcześniej SessionFactory do naszego DAO.
Aby nie wyszło na to, iż przedstawiłem tu tylko suchą teorię, która ma się nijak do rzeczywistości, zaprezentuję w pełni działający przykład. Przykład zawiera jeden obiektu typu DataAccesObject o nazwie AbonentDAO, który realizuje proste operacje CRUD za pomocą NHibernate. Pominę definicję encji Abonent jak i treść pliku mapowania. Oto plik konfiguracyjny dla w pełni działającego przykładu:
<parsers>
<parser type=”Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services” />
<parser type=”Spring.Data.Config.DatabaseNamespaceParser, Spring.Data” />
<parser type=”Spring.Transaction.Config.TxNamespaceParser, Spring.Data” />
</parsers>
<context>
<resource uri=”config://spring/objects” />
</context>
<objects xmlns=”http://www.springframework.net”
xmlns:db=”http://www.springframework.net/database”
xmlns:tx=”http://www.springframework.net/tx”
provider=”SqlServer-2.0″
connectionString=”Data Source=BENIAMINZ\SQLEXPRESS;Initial Catalog=ADMINET;Integrated Security=SSPI;”/>
<property name=”DbProvider” ref=”DbProvider”/>
<property name=”MappingAssemblies”>
<list>
<value>BizDev.SimpleSpringApplication</value>
</list>
</property>
<property name=”HibernateProperties”>
<dictionary>
value=”NHibernate.Connection.DriverConnectionProvider”/>
value=”NHibernate.Dialect.MsSql2005Dialect”/>
value=”NHibernate.Driver.SqlClientDriver”/>
value=”Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12″/>
</dictionary>
</property>
</object>
<object id=”transactionManager”
type=”Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate12″>
<property name=”DbProvider” ref=”DbProvider”/>
<property name=”SessionFactory” ref=”NHSessionFactory”/>
</object>
<object id=”AbonentDao” type=”BizDev.SimpleSpringApplication.AbonentDAO, BizDev.SimpleSpringApplication”>
<property name=”SessionFactory” ref=”NHSessionFactory”/>
</object>
<tx:attribute-driven/>
</objects>
</spring>
Skomentuj