NHibernate in DeltaShell
Wat is NHibernate? Object-Relational Mapper Database /tabel(len)/ rijen Geheugen / Class/ .Net CLR object
Waarom NHibernate? Abstractie boven de DB (db-agnostisch) Minder onderhoud dan sql queries Rijk, ‘oud’ port van Java Hibernate Lazy loading, dirty checking etc Schema-export /update
Configuratie: via app.config <configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate"/> </configSections> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="connection.provider"> NHibernate.Connection.DriverConnectionProvider </property> <property name="dialect"> NHibernate.Dialect.MsSql2005Dialect <property name="connection.driver_class"> NHibernate.Driver.SqlClientDriver <!-- local --> <property name="connection.connection_string"> Server=xp;initial catalog=DataManagerTest;Integrated Security=SSPI <property name='proxyfactory.factory_class'> NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu </session-factory> </hibernate-configuration>
Configuratie : in code (runtime) (Her)Configureren via properties Toevoegen mappings (AddAssemblie) Bepalen naming-strategies Toevoegen DataAccessListeners
NHibernate entititeiten Session Load() Save() Transactions Configuration Mappings Connection String Settings SessionFactory OpenSession
Voorbeeld: VM opslaan en app.config
Nhibernate object states
Configuratie : mapping files 1 hbm.xml file per class Voeg NHibernate.xsd’s toe aan VS Embedded resource!! Zeg zo weinig mogelijk in je mappings Surrogaat key ID
Voorbeeld mapping : Profile <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="IETObjects" assembly="IETObjects"> <class name="Profile" lazy="false" > <id name="DatabaseID" unsaved-value="0" column="ID" type="integer" > <generator class="native"/> </id> <property name="Url" /> <property name="Name" /> <property name="Language" /> <property name="LoginOnce" /> <list name="Screens" cascade="all-delete-orphan" lazy="false" > <key column="profile_id"/> <index column="screen_profile_index" /> <one-to-many class="IETObjects.Screens.Screen" /> </list> <many-to-one class="Administrator" name="Administrator" /> </class> </hibernate-mapping>
Verschillende relaties One-to-many (Map.Layers) Foreign key in child-table Mapping : In Set,List Bag mapping van parent Many-to-one (CoverageLayer.Coverage) Mapping : in childmapping
Verschillende relaties 2 Many-to-many (Variable->Arguments) In aparte koppel tabel Mapping : in Collectie element (List,Set bag etc) One-to-One Relatie tussen primary keys Mapping: in Parent (Person.Address) Not recommended (lazy etc)
One-to-many Parent / Child Map / Layer Mapping in collectie in parent:
One-to-many : tabellen
Many-to-one Mapping in child <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> <class name="IETObjects.Answer, IETObjects" > <id name="DatabaseID" unsaved-value="0" column="ID" type="integer" > <generator class="native"/> </id> <property name="TotalAnswer" /> <many-to-one name="Case" column="caseID" not-null="true" /> <many-to-one name="User“ column="userid" not-null="true"/> </class> </hibernate-mapping>
Many-to-one : tabellen
Many-to-many Mapping aan een of beide kanten <class name=“Artist" > <id name="Id" column="id" type="System.Int64" unsaved-value="0"> <generator class="increment" /> </id> <list name=“Concerts" table=“artist_concerts" > <key column=“artist_id"/> <index column=“artist_list_idx" /> <many-to-many class=“Concert" column=“concert_id" /> </list> </class>
Many-to-many : tabellen
Any-type mappings Foreign key naar willekeurige tabel Mapping in ‘parent’ (a la many-to-one) <class name="Order" table="Orders"> <id name="Id"> <generator class="native"/> </id> <any name="Payment" id-type="System.Int64" meta-type="System.String" cascade="all"> <meta-value value="CreditCard" class="CreditCardPayment"/> <meta-value value="Wire" class="WirePayment"/> <column name="PaymentType"/> <column name="PaymentId"/> </any> </class>
Any-type : tabellen Geen ‘echte’ foreign keys Restrictie in primary key type van gemapped classes Uitzonderings situatie, vaak is er een betere oplossing
Inheritance Table-per-classhierarchy Table-per-subclass Table-per-concrete-class
Inheritance: table-per-classhierarchy Alle entiteiten in 1 tabel Subclass met discriminator Discriminator column voor types Goede performance Sparse tabel Ongewilde relaties tussen subclasses (column types)
Inheritance: table per concrete class Geen associaties op base class niveau Union-subclass Niet genormaliseerd Zelfde property in veel tabellen
Inheritance : table-per-subclass Meest OO (weinig redundantie) Geen wijziging base-class tabellen Lage performance Join(s) voor enkele entiteit
Inheritance :kiezen Table-per-classhierarchy Table-per-subclass Simpel : 1st keus Table-per-subclass Als optie 1 te groot of als er een duidelijke scheiding in het schema moet komen Table-per-concrete-class
Acces-strategies Property : default map naar public property Field: map naar field. Geef fieldnaam op in mapping (als geen naming strategie) NoSetter: als field maar gebruikt property voor Get (Readonly) Custom (eigen class)
Naming-strategies Hoe kom ik van een public property naar het bijbehorende field? Camelcase Camelcase_ Lowercase …
Acces strategy <joined-subclass name="DataItemSet" > <key column="folder_item_id"/> <property name="Tag" access="nosetter.camelcase" /> <!--ensures a list is created on load--> <!--<property access="field" name="isSynchronizedWithList"/>--> <!--type of the list to create EventedList<T> --> <!--<property access="field" name="listType" />--> <property name="itemType" access="field" /> /joined-subclass > </joined-subclass>
Cascade object relaties Eigenaar van object? Zet een cascade op. Object relaties :many-to-one,one-to-many,many-to-many Opties All :save-update-delete van relatie Save-Update : geen delete All-delete-orphan: all+als een object uit alle collecties delete het (orphan) None: object zorgt voor zichzelf
Lazy classes Default is lazy! Alle public accessors (methods properties) moeten virtueel. Proxy objecten Open session is nodig (onhandig voor web)
Usertypes Alleen als niet als anders kan Custom opslag van en naar byte[] Geen foreign keys Geen updates Voorbeeld : GeometryUserType
DeltaShell: Database structuur Project is root Zorg voor juiste ‘cascade’ regels zodat je object opgeslagen wordt.
DataItem Value Types Any type mapping: foreign key naar meerdere tabellen Zorg er voor dat je object wordt teruggeven door een DataProvider.SupportedDataObjectNames
DataAccessListeners Herschijft bestands namen Reconnect bij save-as Run code bij bepaalde database acties (pre-insert, post-load etc) Nu alleen FileBased DAL. Herschijft bestands namen Reconnect bij save-as public bool OnPreInsert(object entity, object[] state, string[] propertyNames) { if (entity is IFileBased) MakePathRelative(entity as IFileBased, state, propertyNames); } return false;//no veto
Mappen van Modellen Voeg modeldata toe in DataItems Map de modeldata data classes Zorg ervoor dat deze classes in de any-type van DataItem terecht komen via dataProviders. OF : maak custom mappings
NHibernate binnen test NHibernate configuratie is static Voeg zelf assemblies toe met NHibernateProjectRepository.RegisterAssembly() Voeg DataItem ValueType mappings toe met NHibernateProjectRepository.RegisterDataItemValueType Reset static configuratie met NHibernateProjectRepository.ResetConfiguration()
Veel voorkomende fouten Key not found exception -> DataItemType Event registratie en Nhibernate Nhibernate set properties dus unsubscribe/subscribe daar. Unmapped class Geen embedded resource?
Nhibernate Profiler Demo in VM. Download trial van Ayende
NHibernate Linq IQueryable SQL Demo2 in VM
Nog meer!!? NHibernate in Action van manning Ayende’s blog ActiveRecord Fluent-Nhibernate