Sean Chambers Senior Developer at Flagler County Schools for 5 years Owner Hybrid Software, Educational Software Contributor to various open source projects (Castle Project, Nhibernate, NUnit, NBehave) Practicing TDD,DDD,BDD for 2 years Blog: http://schambers.lostechies.com Twitter: schambers ORM stands for Object Relational Mapper Maps your POCO (plain old clr objects) to your relational model using XML config Relieves developer from 95% of common CRUD code MSSQL 2000, 2005 etc.. SqlCe, Sqlite, Firebird embedded db’s MySQL PostgreSql Oracle SyBase Db2 Many many more Domain Model Persistence Layer NHibernate Session SessionFactory Database Configuration SessionFactory Session 1. SessionFactory consumes the configuration 2. Shared among all application threads 3. Instantiation is expensive as parsing of mapping files is performed 4. Validates mapping files, showing errors if incorrect mapping 5. SessionFactory provides Session objects that are used to interact with the database 6. A Session object holds an open connection to the database for loading objects, and transaction management 1. Web.config/app.config 2. Mapping files Configuration defines db dialect, db connection and mapping files assembly Sample mapping file: <class name=“Order” table=“Orders”> <id name="Id" type=”int" column=“OrderId" unsaved-value="0"> <generator class=”native"/> </id> <property name=“Total” /> <many-to-one name=“Customer” /> </class> Manages interaction with database, contains all basic CRUD operations ◦ session.Get(typeof(Order), orderId); ◦ Session.Load(typeof(Order), orderId); will throw exception ◦ session.Save(myOrder); ◦ session.SaveOrUpate(myOrder); ◦ Session.Delete(myOrder); Query/HQL API Criteria API Native SQL Nhibernate contains an extremely powerful querying API IQuery ◦ Provides a method for building a DB query through HQL (hibernate query language) IQuery q = session.CreateQuery(“from Orders where Total>:total”) .SetDecimal(“Total”, 30m) .OrderBy(Order.Asc(“Title”)) .SetFirstResult(20) .SetMaxResults(10); IList<Order> orders = q.List<Order>(); Constructs a query using an API Is more extensible than HQL ICritiera crit = session.CreateCriteria(typeof(Order)) .Add(Expression.Gt(“Total”, 30m)) .SetFirstResults(20); IList<Order> orders = crit.List<Order>(); Allows you to execute native SQL queries Good for legacy adoption IList<Order> orders = session.CreateSqlQuery(“select {order.*} from Order {order} where {order.Total} < 30.00”), “order”, typeof(Order)) .List<Order>(); NHibernate will track changes performed to an object a.k.a. “Dirty” objects Will implicitly call Save: Order order = session.Load(typeof(Order), orderId); order.Total = 69.95m; session.Flush(); Flush() is also called when transaction is committed Collection Mapping Component Mapping Inheritance Mapping One of the more complex aspects of NHibernate Different collection types: ◦ ◦ ◦ ◦ bag : collection of values that are not distinct list : collection of values that have an index set : distinct set of values map :hash/dictionary. Keys and value Bag and List map to IList<T>, bag with caveats (add method) Set maps to Iesi.Collections.Generics.HashedSet<T> Map maps to IDictionary<K, V> Maps an objects associations into a single table Good for value objects that do not require an identity (DDD) Customer.Address with Street and City fields would map to: Table: Street, Columns AddressStreet, AddressCity etc… <class name=“Customer” table=“Customer”> <property name=“FirstName” /> <property name=“LastName” /> <component name=“Address”> <property name=“Street” /> <property name=“City” /> </component> </class> Three different strategies for mapping inheritance hierarchies Table per class hierarchy (1 table total) ◦ Uses a discriminator to identify the type of the row ◦ Will have null values for certain columns Table per subclass (1+n tables) ◦ One for the base class, one table for each subclass Table per concrete class (n tables) ◦ No table for the base class Fluent NHibernate ◦ http://code.google.com/p/fluent-nhibernate/ This tool was just recently forked from Jeremy Miller’s StructureMap Absolutely necessary with any ORM Inserts proxies at traversal points Once navigation to assoc./collection is performed, NHibernate will retrieve data on-the-fly and replace the proxy object Can modify behavior to “Eager” load related objects Can be problematic in certain scenarios, namely JSON serialization Saves you from loading an entire object graph when all you need is a subset of data Legacy applications ◦ Often, it is difficult to make your model map to your established db structure, not impossible however ETL/Data Mining scenarios Small Domain Models/No Domain Model Good post on performance benchmarks: http://www.iamnotmyself.com/2008/07/02/NHibernateTestingThePerforma nceUrbanLegend.aspx Performance benchmark results Test 1st Run Nth Run Inline SQL 1312.5ms ~430ms Parameterized Query 1296.9ms ~350ms SPROC 1390.6ms ~320ms NHibernate 1565.3ms ~560ms NHibernate w/Transaction 1406.3ms ~300ms nth Run