NHibernate in DeltaShell Wat is NHibernate? • Object-Relational Mapper Geheugen / Class/ .Net CLR object Database /tabel(len)/ rijen Waarom NHibernate? • Abstractie boven de DB (dbagnostisch) • 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> <property name="connection.driver_class"> NHibernate.Driver.SqlClientDriver </property> <!-- local --> <property name="connection.connection_string"> Server=xp;initial catalog=DataManagerTest;Integrated Security=SSPI </property> <property name='proxyfactory.factory_class'> NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu </property> </session-factory> </hibernate-configuration> Configuratie : in code (runtime) • (Her)Configureren via properties • Toevoegen mappings (AddAssemblie) • Bepalen naming-strategies • Toevoegen DataAccessListeners NHibernate entititeiten Configuration SessionFactory •Mappings •Connection String •Settings •OpenSession Session •Load() •Save() •Transactions 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) – Foreign key in child-table – 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-toone) <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-perclasshierarchy • 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-persubclass • Meest OO (weinig redundantie) • Geen wijziging base-class tabellen • Lage performance • Join(s) voor enkele entiteit Inheritance :kiezen • Table-per-classhierarchy – 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 Folder Model DataItem Coverage Map Layer •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 • Run code bij bepaalde database acties (pre-insert, postload 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