Exploring the NHibernate Ecosystem Steve Bohlen EMail sbohlengmail
Exploring the NHibernate Ecosystem Steve Bohlen E-Mail: sbohlen@gmail. com Blog: http: //blog. unhandled-exceptions. com Twitter: @sbohlen
Steve Bohlen Nearly 20 years developing software LISP, Pascal, C/C++, VB. NET, C# Co-Founder, NYC Alt. Net User Group http: //nyalt. net Contributor: various OSS projects http: //www. summerofnhibernate. com blog: http: //blog. unhandled-exceptions. com e-mail: sbohlen@gmail. com twitter: @sbohlen
Oredev 2009: Efficiency NHibernate Add-ins NHibernate-based Frameworks Object Relational Mapping with NHibernate Persistence Framework Relational Persistence
Coming Up: A Tour Malmo
…Not a Deep Dive
Mapping the Universe The NHibernate Ecosystem
NH Caches Rhino Tools NH Search u. NHAddins NH Spatial NH Burrow NH Mapping Attributes NH Shards Jet. Driver NH Validator NH Linq Castle Active. Record Fluent. NH Lambda Extensions Castle NH Facility NH Prof Castle Active. Writer NH Proxy Gen NHContrib External NHibernate Core
Relational Data Sources Non-Relational Data Sources NHSpatial Jet. Driver NHSearch NHibernate Core Lambda Extensions NH Validator NH LINQ NH Attribute Mapping Castle Active. Record Fluent. NH Mapping, Configuration, and Query Rhino Tools u. NHAddins NHBurrow Castle NH Facility NH Caches Infrastructure and Frameworks
NHibernate Implementation Framework (plus a lot more) Rhino. Tools
A Complete Infrastructure Stack � Unit-of-Work Abstraction � Io. C Container Convenience Services �Assumes Castle Windsor � NH Session lifecycle management for ASP. NET apps � Conversation-per-Business-Transaction � NHRepository<T> implementation � Multiple, concurrent DB support � Lots more
Rhino IRepository<T> public interface IRepository<T> { // Methods long Count(); long Count(Detached. Criteria criteria); T Create(); Detached. Criteria Create. Detached. Criteria(string alias); void Delete(T entity); void Delete. All(Detached. Criteria where); object Execute. Stored. Procedure(string sp_name, params Parameter[] parameters); ICollection<T 2> Execute. Stored. Procedure<T 2>(Converter<IData. Reader, T 2> converter, string sp_name, params Parameter[] parameters); bool Exists(Detached. Criteria criteria); ICollection<T> Find. All(params ICriterion[] criteria); ICollection<T> Find. All(Order order, params ICriterion[] criteria); ICollection<T> Find. All(Order[] orders, params ICriterion[] criteria); ICollection<T> Find. All(Detached. Criteria criteria, params Order[] orders); ICollection<T> Find. All(string named. Query, params Parameter[] parameters); ICollection<T> Find. All(int first. Result, int number. Of. Results, params ICriterion[] criteria); ICollection<T> Find. All(Detached. Criteria criteria, int first. Result, int max. Results, params Order[] orders); ICollection<T> Find. All(int first. Result, int number. Of. Results, Order selection. Order, params ICriterion[] criteria); ICollection<T> Find. All(int first. Result, int number. Of. Results, string named. Query, params Parameter[] parameters); ICollection<T> Find. All(int first. Result, int number. Of. Results, Order[] selection. Order, params ICriterion[] criteria); T Find. First(params Order[] orders); T Find. First(Detached. Criteria criteria, params Order[] orders); T Find. One(params ICriterion[] criteria); T Find. One(Detached. Criteria criteria); T Find. One(string named. Query, params Parameter[] parameters);
Abstractions, Tools, and a WHOLE lot more! u. Nh. Addins
u. Nh. Addins: a Smörgåsbord! NH User. Types NH Session Mgt for WCF NH Session Mgt for WPF Io. C Container Abstraction Castle Windsor Adapter Inflector NH Audit Event Listeners Spring. NET Adapter Ninject Adapter Query Pagination NH Event Listeners Conversation. Per-Business Transaction NH Session Abstraction Tolerant Query Cache http: //unhaddins. googlecode. com Validation Abstraction NH Validator Adapter Data Annotations Adapter Castle Validator Adapter Validation Ent. Application Block Adapter
Efficient Database Caching NHibernate Caches
Cache Providers � Mem. Cache � Implementation for Mem. Cached � http: //memcached. googlecode. com � Prevalence � Bamboo. Prevalence engine � http: //bbooprevalence. sourceforge. net � Shared. Cache � Inspired by Mem. Cached but 100% managed code (C#) � http: //www. sharedcache. com � Velocity � Microsoft’s Distributed Caching Engine (CTP 2) � Sys. Cache � ASP. NET Cache Provider � Sys. Cache 2 � ASP. NET Cache Provider ○ with SQLServer call-back-invalidate support
Simpler Data Access Castle Active. Record
Active. Record Example [Active. Record] public class Category : Active. Record. Base { [Primary. Key] public int Id { get; set; } [Property] public string Name { get; set; } [Belongs. To("parent_id")] public Category Parent { get; set; } [Has. Many] public IList<Category> Sub. Categories { get; set; } }
Integrated Validation Framework NHibernate Validator
Using NHValidator Get and Build it (NHContrib) 2. Add References 3. Register Event Listeners 1. � in code or hibernate. cfg. xml file 4. Off and Running!
Let’s Look at Some Code! NHibernate Validator Demo
Death to String-Literals!!!! NHLambda. Extensions
Using NHLambda. Extensions Download the Assembly (googlecode) Add Reference to Assembly 2. Off and Running! 1.
Lambda. Extensions In Action session. Create. Criteria<Customer>(). Add(Restrictions. Eq(“Firstname”, “Steve”). List<Customer>(); session. Create. Criteria<Customer>(). Add<Customer>(c => c. Firstname == “Steve”). List<Customer>();
One Query Language to Rule Them All! NHLINQ (not LINQ to Nhibernate…yet!)
Using NHLINQ 1. Download the Assembly (sourceforge) � v 1. 0 NH 2. 1 GA release Add Reference to Assembly 3. Off and Running! 2.
NHLINQ in Action using (var session = session. Factory. Open. Session()) { using (var tx = session. Begin. Transaction()) { var customers = session. Linq<Customer>(). Where(c => c. Firstname == “Steve”); foreach (var customer in customers) { Console. Write. Line(customer. Firstname); } tx. Commit(); } }
Stateful NHibernate Session Management for ASP. NET Web. Forms NHibernate Burrow
Using Burrow Get it and Build it (NHContrib) 2. Add References 3. Add NHibernate. Burrow config section to web. config 4. Add Burrow HTTP Module to your web. config 1.
Modify web. config for Burrow <config. Sections> <section name="NHibernate. Burrow“ type="NHibernate. Burrow. Configuration. Nhibern ate. Burrow. Cfg. Section, NHibernate. Burrow" /> </config. Sections> <NHibernate. Burrow> <persistence. Units> <add name="Persistence. Unit 1" nh-config-file = “~/hibernate. cfg. xml“ /> </persistence. Units> </NHibernate. Burrow>
Register Burrow HTTPModule <http. Modules> <add name="NHibernate. Burrow. Web. Util. Http. Module” type="NHibernate. Burrow. Web. Util. HTTPModule, NHibernate. Burrow. Web. Util"/> </http. Modules>
Burrow Conversation Pattern Burrow. Framework bf = new Burrow. Framework(); bf. Current. Conversation. Span. With. Post. Backs(Transaction. Strat egy. Business. Transaction); //do a bunch of work in a bunch of postbacks Burrow. Framework bf = new Burrow. Framework(); bf. Current. Conversation. Finish. Span(); //commit to DB… bf. Current. Conversation. Give. Up(); //…or abandon!
Spatial Queries NHibernate Spatial
Understanding Spatial Data Latitude / Longitude Coordinate Systems (Spatial Reference ID) SRID Projections
Supported Spatial Engines � MS SQLServer 2008 �Includes SQLServer 2008 Express! � My. SQL � Post. GIS (Post. Gre-based) � Oracle (work-in-progress)
Using NH Spatial 1. 2. 3. 4. 5. 6. Get and Build it (NHContrib) Add References (Geo. API, Spatial, etc. ) Change Dialect in hibernate. cfg. xml Optional: add support for spatial metadata to the Configuration instance before building Session. Factory Map properties as ‘Geometry Type’ Off and Running!
NHSpatial: Dialect <? xml version="1. 0" encoding="utf-8"? > <hibernate-configuration xmlns="urn: nhibernate-configuration-2. 2" > <session-factory name="NHibernate. Test"> <property name="connection. driver_class">NHibernate. Driver. Sql. Client. Driver</property> <property name="connection_string"> Server=(local); initial catalog=nhibernate; Integrated Security=SSPI </property> <property name="adonet. batch_size">10</property> <property name="show_sql">false</property> <property name="dialect“> NHibernate. Spatial. Dialect. Ms. Sql 2008 Spatial. Dialect, NHibernate. Spatial. Ms. Sql 2008 </property> <property name="use_outer_join">true</property> <property name="command_timeout">60</property> <property name="query. substitutions">true 1, false 0, yes 'Y', no 'N'</property> <property name="proxyfactory_class"> NHibernate. Byte. Code. Lin. Fu. Proxy. Factory, NHibernate. Byte. Code. Lin. Fu </property> </session-factory> </hibernate-configuration>
Add Spatial Metadata Classes Configuration cfg = new Configuration(); cfg. Configure(); Metadata. Add. Mapping(cfg, Metadata. Class. Geometry. Column); Metadata. Add. Mapping(cfg, Metadata. Class. Spatial. Reference. System); var session. Factory = cfg. Build. Session. Factory(); //rest of your app here!
Add Geometry Type + Mapping using Geo. API. Geometries public class My. Thing { public virtual IGeometry {get; set; } //more of our class } <!-- short version --> <property name="Geometry" column="the_geom" type = "NHibernate. Spatial. Type. Geometry. Type, NHibernate. Spatial" /> <!-- long version --> <property name="Geometry" column="the_geom"> <type name = "NHibernate. Spatial. Type. Geometry. Type, NHibernate. Spatial"> <param name="srid">4326</param> <param name="subtype">POLYGON</param> </type> </property>
Perform Spatial Queries var country = session. Create. Criteria<Country>(). Add(Spatial. Expression. Contains("Boundaries", new Point( -70. 40, -33. 24))). Unique. Result<Country>(); IList<Town> towns = session. Create. Criteria<Town>(). Add(Spatial. Expression. Filter("Boundaries", new Envelope(-70, -68, -32, -34))). Add(Restrictions. Not(Spatial. Expression. Contains("Bounda ries", new Point(-70. 40, -33. 24)))). List<Town>();
Querying Unstructured Text Indices NHibernate Search
The Power of Lucene. NET � Databases are efficient and querying relational data � Databases are inefficient at querying unstructured text � Better tools exist to do that �Lucene. NET ○ A port of the Lucene project to. NET ○ High-performance indexed searching of text content
NHibernate Search Select all Customers who have more than 10 orders and whose comments on their Invoices contain the word “’dissatisfied” Relational Database NHibernate Query Lucene. NET Document Index
Using NHSearch 1. 2. 3. 4. 5. 6. Get and build it (NHContrib) Add References Add index-related properties to hibernate. cfg. xml Register Ins, Upd, Del event listeners to trigger updates to index on change Add attributes to your classes to indicate what should be indexed Off and Running!
Modify Configuration File <? xml version="1. 0" encoding="utf-8"? > <hibernate-configuration xmlns="urn: nhibernate-configuration-2. 2" > <session-factory name="NHibernate. Test"> <property name="connection. driver_class">NHibernate. Driver. Sql. Client. Driver</property> <property name="connection_string"> Server=(local); initial catalog=nhibernate; Integrated Security=SSPI </property> <property name="adonet. batch_size">10</property> <property name="show_sql">false</property> <property name="dialect">NHibernate. Dialect. Ms. Sql 2000 Dialect</property> <property name="use_outer_join">true</property> <property name="command_timeout">60</property> <property name="query. substitutions">true 1, false 0, yes 'Y', no 'N'</property> <property name="proxyfactory_class"> NHibernate. Byte. Code. Lin. Fu. Proxy. Factory, NHibernate. Byte. Code. Lin. Fu </property> <property name=“hibernate. search. default. directory_provider”> NHibernate. Search. Store. FSDirectory. Provider, NHibernate. Search </property> <property name=“hibernate. search. default. index. Base”>c: My. Index</property> <property name=“hibernate. search. indexing_strategy”>event</property> </session-factory> </hibernate-configuration>
Register Event Listeners <!-- register in hibernate. cfg. xml file --> <listener class = “NHibernate. Search. Event. Full. Text. Index. Event. Listener, NHibernate. Search” type=“post-insert”/> <listener class = “NHibernate. Search. Event. Full. Text. Index. Event. Listener, NHibernate. Search” type=“post-update”/> <listener class = “NHibernate. Search. Event. Full. Text. Index. Event. Listener, NHibernate. Search” type=“post-delete”/> //register in code var cfg = new Configuration(); cfg. Set. Listener(NHibernate. Event. Listener. Type. Post. Update, new Full. Text. Index. Event. Listener()); cfg. Set. Listener(NHibernate. Event. Listener. Type. Post. Insert, new Full. Text. Index. Event. Listener()); cfg. Set. Listener(NHibernate. Event. Listener. Type. Post. Delete, new Full. Text. Index. Event. Listener());
Add Attributes for Index Engine public class Document { [Document. Id] public virtual int Id { get; set; } [Field(Index. Tokenized, Store=Store. Yes)] public virtual string Title { get; set; } [Field(Index. Tokenized)] public virtual string Body { get; set; } }
Perform Indexed Queries using (var session = session. Factory. Open. Session()) { using(var textsearch = Search. Create. Full. Text. Session(session)) { using (var tx = session. Begin. Transaction()) { var results = textsearch. Create. Full. Text. Query<Document>(“Title: Oredev"). Set. Max. Results(10). List<Document>(); } } }
Mapping and Configuration without XML Fluent NHibernate
Using Fluent. NHibernate Get it ( http: //fluentnhibernate. org ) 2. Add References 3. Off and Running! 1.
Sample Classes
XML Mappings <? xml version="1. 0" encoding="utf-8" ? > <hibernate-mapping xmlns="urn: nhibernate-mapping-2. 2" assembly="Fluent. NHibernate. Demo" namespace="Fluent. NHibernate. Demo" > <class name="Customer"> <id name="Id" column="Customer. Id" type="integer"> <generator class="native" /> </id> <property name="Firstname" type="string"/> <property name="Lastname" type="string"/> <set name="Orders" table="`Order`" generic="true" inverse="true"> <key column="Customer. Id"/> <one-to-many class="Order"/> </set> </class> </hibernate-mapping>
Fluent Mappings public class Customer. Map : Class. Map<Customer> { public Customer. Map() { Id(c => c. Id). Column("Customer. Id"); Map(c => c. Firstname); Map(c => c. Lastname); Has. Many<Order>(c => c. Orders). Table("Order"). Key. Column("Customer. Id"). Inverse(). Generic(); } }
XML Configuration <? xml version="1. 0" encoding="utf-8"? > <hibernate-configuration xmlns="urn: nhibernate-configuration-2. 2" > <session-factory name="NHibernate. Test"> <property name="connection. driver_class">NHibernate. Driver. Sql. Client. Driver</property > <property name="connection_string"> Server=(local)sqlserver 2005; initial catalog=Fluent. NHibernate. Demo; user=sa; password=password </property> <property name="adonet. batch_size">10</property> <property name="show_sql">true</property> <property name="dialect">NHibernate. Dialect. Ms. Sql 2005 Dialect</property> <property name="use_outer_join">true</property> <property name="command_timeout">60</property> <property name="query. substitutions">true 1, false 0, yes 'Y', no 'N'</property> <property name="proxyfactory_class">NHibernate. Byte. Code. Castle. Proxy. Factory. F actory, NHibernate. Byte. Code. Castle</property> <mapping assembly="Fluent. NHibernate. Demo"/> </session-factory> </hibernate-configuration>
Fluent Configuration session. Factory = Fluently. Configure(). Database(Fluent. NHibernate. Cfg. Db. Ms. Sql. Configuration. Ms Sql 2005. Connection. String(CONNSTRING). Ado. Net. Batch. Size(10). Proxy. Factory <NHibernate. Byte. Code. Castle. Proxy. Factory>(). Use. Outer. Join()). Mappings(m => m. Fluent. Mappings. Add. From. Assembly. Of<Customer. Map>()). Build. Session. Factory();
Convention Mapping � Enables Fluent NHibernate to ‘infer’ your mappings from your objects � Uses conventions �Baked into FNH �Overrides provided by yourself �Identity field convention �Many-to-many intermediate table convention �Foreign-key id column convention �Many, many more
Production-Class Profiling for ORMs NH Prof
Metrics, Analysis, Recommendations
Summary � If you’re doing your data-access by hand… �YOU’RE DOING IT WRONG � If you’re doing the rest of the stuff you saw here today by hand… �YOU’RE DOING IT WRONG � NHibernate has one of the richest ecosystems of extensions, frameworks, and tools of any. NET technology, OSS or otherwise… �LEARN TO LEVERAGE THEM for EFFICIENCY
*NHibernate 2. 1. 1 GA Released!* � November 1, 2009 � Probably the final 2. x release before 3. 0 � Primarily bug-fix, no breaking changes � Most of these tools will work with 2. 1. 1 �Most will need to be recompiled against the new release before use ○ Binary dependency on NH assemblies � HORNGET. NET is your friend here!
Resources � NHForge �http: //www. nhforge. org � NHContrib �http: //sourceforge. net/projects/nhcontrib � u. Nh. Addins �http: //u. Nh. Addins. googlecode. com � NHProf �http: //www. nhprof. com � Horn. Get. NET �http: //www. hornget. net
~fini~
- Slides: 62