cz.1

advertisement
1.
Pobranie i instalacja NHibernate
- nhforge.org -> download, rozpakować, i zapamiętać, gdzie jest (<katalog>)
- nhforge.org -> getting started, manual
2.
Użycie w projekcie:
- dodanie referencji
- <katalog>\Required_Bins\NHibernate.dll
- <katalog>\Required_For_LazyLoading\Spring\NHibernate.ByteCode.Spring.dll
(do obsługi lazy loading)
- ustawienie opcji projektu (architektura celu: x86) (na x86-64 jest problem z ADO)
- przestrzenie nazw:
- using NHibernate;
- using NHibernate.Cfg;
- dodanie pliku konfiguracyjnego
- <katalog>\Configuration_Templates -> można wybrać odpowiedni dla bazy
- w naszym przypadku: kod poniżej (dodać do projektu w nhibernate.cfg.xml)
- ustawić property connection.connection_string
- ustawić property proxyfactory.factory_class na Spring (zmienić LinFu na Spring)
- property show_sql – jeżeli ma wartość true, to na konsoli będą wyświetlane wszystkie zapytania do bazy
(ustawić, żeby zaobserwować leniwe ładowanie)
- property query.substitutions – możliwość podmiany wartości w zapytaniach
- property connection.release_mode – zarządzanie połączeniem z bazą (ADO) (bez tego, mogą czasem
wyskakiwać wyjątki)
- dodać jako ostatnie property: mapping_assembly – nazwa assembly w którym będą zapisywane klasy
- ustawienie we właściwościach: copy to output: always (zawsze kopiuj plik to katalogu z binarką)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSqlCeDialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.connection_string">TU WPISAC CONNECTION STRING</property>
<property name="connection.driver_class">NHibernate.Driver.SqlServerCeDriver</property>
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.Spring.ProxyFactoryFactory, NHibernate.ByteCode.Spring
</property>
<property name="show_sql">False</property>
<property name="connection.release_mode">on_close</property>
<mapping assembly="TU WPISAC NAZWE ASSEMBLY" />
</session-factory>
</hibernate-configuration>
</configuration>
-
-
utworzenie bazy danych (w SqlServer CE)
- dodanie referencji: System.Data.SqlServerCe.dll
- program files [x86]->MS SQL Server Compact Edition\v3.5\desktop\...
- properties -> copy local ustawić na true
- projekt -> add item -> local database
- we właściwościach (okienko baz danych, nie projektu) *.sdf -> Connection string -> skopiować do pliku
konfiguracyjnego
utworzenie konfiguracji (w main-ie):
Configuration cfg;
cfg = new Configuration();
cfg.Configure(); // szuka w lokalnym katalogu “hibernate.cfg.xml”
//LUB:cfg.Configure("hibernate.cfg.xml"); <- z nazwą pliku z konfiguracją
-
utworzenie fabryki sesji:
- fabryka sesji jest „ciężkim” obiektem – tworzyć tylko jedną na konfigurację
ISessionFactory sessionFactory;
sessionFactory = cfg.BuildSessionFactory();
...
sessionFactory.Close();
-
utworzenie sesji
- sesja jest „lekka”
- operacje na bazie będą wykonywane jako metody sesji
- metoda Flush() – wymuszenie zapamiętania w bazie wszystkich zmian (podobnie jak fflush na plikach)
ISession currentSession;
currentSession = sessionFactory.OpenSession();
...
currentSession.Flush()
currentSession.Close();
3.
Trwała klasa:
- definicja kodu klasy
- klasa publiczna (bez tego nie skorzystamy z leniwego ładowania)
- publiczny bezparametrowy konstruktor (może być domyślny)
- wirtualne properties (hibernate tworzy obiekty proxy wywodząc je z naszej klasy – nadpisuje properties, więc
muszą być wirtualne)
- powinna mieć property, które będzie identyfikatorem obiektu (tak jak id w bazie danych)
- dla NHibernate, dwa obiekty o tym samym identyfikatorze to te same id; biblioteka będzie nam
gwarantowała (w większości sytuacji – o tym później) że jeżeli id dwóch obiektów jest takie samo, to jest
to ten sam obiekt (w pamięci)
class Klasa
{
public Klasa() {}
public virtual int id { get; set; }
public virtual string data { get; set; }
}
- powiązanie klasy z jej bazodanową reprezentacją – plik hbm (nazwa_klasy.hbm.xml)
- właściwości -> build action: embedded resource – hibernate przegląda osadzone zasoby w poszukiwaniu
plików *.hbm.xml i pobiera z nich opisy obiektów)
- plik ten opisuje klasę: nazwa klasy, assembly w którym się znajduje, nazwa tabeli w bazie danych, w której
będą przechowywane dane oraz właściwości, które mają być pamiętane
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="NAZWA NAMESPACE" assembly="NAZWA ASSEMBLY">
<class name="NAZWA KLASY" table="NAZWA TABELI W BAZIE DANYCH">
<id name="id"><generator class="native" /></id>
<property name="data" column="napis"/>
</class>
</hibernate-mapping>
- węzeł id – opisuje właściwość, która jest identyfikatorem obiektu
- węzeł generator – opisuje, w jaki sposób będą generowane wartości dla tworzonych elementów
- klasa assigned – użytkownik jest odpowiedzialny za przydzielanie identyfikatorów
- klasa native – „autoincrement” właściwy dla bazy danych (identity/sequence/hilo)
- increment – działa tylko, gdy jeden proces równocześnie wstawia dane
- identity – identity columns in DB2, MySQL, MS SQL Server and Sybase
-
-
4.
- sequence – sequence in DB2, PostgreSQL, Oracle or a generator in Firebird
- ...
- typowe parametry:
- name – nazwa property w klasie
- column (opcjonalne) – nazwa kolumny w tabeli, w której property zostanie zachowana
- type (opcjonalne) – typ identyfikatora
węzły property – opisują pozostałe właściwości
- każdą właściwość, która ma być zachowana, należy opisać
- typowe parametry:
- name (wymagane) – nazwa property w klasie
- column (opcjonalne) – nazwa kolumny w tabeli, w której property zostanie zachowana
- type (opcjonalne) – typ właściwości
- NHibernate jest w stanie zapamiętać, bez dodatkowego wysiłku z naszej strony, wszystko, co jest
serializowalne (ISerializable) – byle był w stanie przełożyć to na zawartość kolumny w bazie (dla
ISerializable potrzebna jest kolumna typu varbinary/blob/itp.)
tabela w bazie danych
- tabele można utworzyć ręcznie (wtedy trzeba pamiętać o zgodności tabeli z opisem)
- gdy nie podamy parametry column, to kolumna musi nazywać się tak samo jak właściwość
- typy kolumn powinny być zgodne z typami properties „w rozsądnym zakresie”
- biblioteka jest w stanie przechowywać np. liczbę w kolumnie typu varchar, ale w drugą stronę sobie
nie poradzi
- automatyczne tworzenie/aktualizacja tabel:
- namespace NHibernate.Tool.hbm2ddl
- new SchemaExport(cfg).Execute(false, true, false);
- cfg – obiekt konfiguracji (już skonfigurowany)
- pierwszy parametr – czy wyświetlać na konsolę utworzony opis (create-y)
- drugi parametr – czy rzeczywiście wykonać ddl na bazie
- trzeci parametr – jeżeli true, to będą wykonane tylko drop-y (usunięcie tabel, bez tworzenia)
- np. false, true, false – utwórz na nowo wszystkie tabele
- np. false, true, true – tylko usuń tabele (np. po wykonaniu testów)
- np. true, false, false – wyświetl, to co byłoby zrobione, ale nic nie wykonuj
- stare dane zostaną usunięte!
- new SchemaUpdate(cfg).Execute(false, true);
- parametry takie jak pierwsze dwa parametry SchemaExport
Podstawowe operacje:
- 3 stany obiektu
- przejściowy – nie ma przydzielonego trwałego identyfikatora (np. zaraz po utworzeniu obiektu, kiedy nie
został jeszcze zapisany w bazie)
- trwały – ma trwały identyfikator i może być już powiązany z wierszem w bazie danych; przypisany jest do
istniejącej, otwartej sesji; w tym stanie gwarantowane jest, że jeżeli dwa obiekty mają takie samo id, to jest to
ten sam obiekt „w pamięci”; w tym stanie operacje na obiekcie będą „automagicznie” utrwalane w bazie
danych
- odłączony – ma przypisany trwały identyfikator i być może wiersz w bazie, ale sesja w której istniał została
zamknięta lub obiekt został przeserializowany do innego procesu; nie mamy gwarancji z drugiego punktu
- utworzenie obiektu: tak, jak wszystkie obiekty – new NazwaTypu() (obiekt w stanie przejściowym)
- zapisanie w bazie: (obiekt staje się trwały)
- currentSession.Save(obiekt)
- currentSession.Save(obiekt, id_dla_niego) (jeżeli id jest assigned i jeszcze nie przypisaliśmy id do obiektu)
- odczytanie obiektu z bazy
- currentSession.Get<Typ>(id_obiektu_do_odczytania)
- np Klasa k = currentSession.Get<Klasa>(10);
- jeżeli obiekt nie istnieje w bazie, zostanie zwrócone null
- jeżeli obiekt był już wcześniej odczytany, otrzymamy referencję na niego:
k = s.Get<Klasa>(1);
Console.WriteLine("k.d = " + k.data); // wypisze „abc”
k.data = "def";
Klasa k2 = s.Get<Klasa>(1);
Console.WriteLine("k2.d = " + k.data); // wypisze „def”
-
5.
// k2 jest tym samym obiektem co k
usunięcie: currentSession.Delete(obiekt) (obiekt, nie jego id !)
Update / SaveOrUpdate
transakcje
- mechanizm jak w SQL
ITransaction t = currentSession.BeginTransaction();
//LUB:ITransaction t =
//
currentSession.BeginTransaction(System.Data.IsolationLevel.*);
...
t.Commit();
t.Rollback();
Zapytania i HQL
- interfejs IQuery
IQuery q = currentSession.CreateQuery("from Klasa k"); // Klasa: nazwa TYPU!
IEnumerable<Test> data;
// IList<Klasa> data;
data = q.Enumerable<Klasa>();
// data = q.List<Klasa>();
foreach(Klasa v in data)
Console.WriteLine("Klasa({0},\”{1}\”)", v.id, v.data);
-
parametrem do CreateQuery jest zapytanie w języku HQL
- HQL to taki SQL, w którym zamiast nazw tabel i kolumn mamy typy (klasy) i ich pola
- np. „from Klasa k where k.id < 10” – „select *” można pominąć
- obsługuje większość konstrukcji z SQL:
- case insensitive (poza nazwami klas)
- from Namespace.Class
- from Namespace.Class as c – alias
- from Namespace.Class c – alias j.w.
- from A, B – iloczyn kartezjański
- inner join
- left outer join
- right outer join
- where – warunki (nazwy pól klas a nie kolumn!)
- is null
- is not null
- between ‘A’ and ‘B’
- in ( ‘Foo’, ‘Bar’, ‘Baz’)
- select ... from ... – wybrane pola z klasy – wartością elementami kolekcji będą:
- jeżeli wybieramy tylko jedno pole – obiekty typu tego pola
- jeżeli wybieramy kilka pol – będą „siedzieć” w tablicy obiektów
- IList<object []> data = ..CreateQuery(„select id, data from Klasa k”).List<object []>();
- (int)(data[0][0]) = id, (string)(data[0][1]) = data
- parametry zapytania
- pozycyjne: ? („where k.id=?”)
- nazwane: :nazwa (dwukropek nazwa) („where dana=:param”)
- IQuery::SetString/SetInt32/SetParameter/Set...(nazwa_lub_numer, obiekt)
- nazwa_lub_numer to numer parametru pozycyjnego (liczba, licząc od 0) lub nazwa parametru
nazwanego (string)
- obiekt – wartość do nadania parametrowi
- IQuery::SetFirstResult(numer) – numer pierwszego zwróconego wiersza
- IQuery::SetMaxResults(liczba) – ustawienie maksymalnej liczby zwróconych wierszy
Download