Intro To S.O.L.I.D. - Unhandled Exceptions: When Software

Download Report

Transcript Intro To S.O.L.I.D. - Unhandled Exceptions: When Software

Exploring the NHibernate Ecosystem
Steve Bohlen
E-Mail: [email protected]
Blog: http://blog.unhandled-exceptions.com
Twitter: @sbohlen
Steve Bohlen
Nearly 20 years developing software
LISP, Pascal, C/C++, VB, 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: [email protected]
twitter: @sbohlen
Oredev2009: Efficiency
NHibernate
Add-ins
NHibernate-based Frameworks
Object Relational Mapping with NHibernate
Persistence Framework
Relational Persistence
Coming Up: A Tour
…Not a Deep Dive
Mapping the Universe
NH Caches
Rhino Tools
NH Search
uNHAddins
NH Spatial
NH Burrow
NH Mapping
Attributes
NH Shards
JetDriver
NH Validator
NH Linq
Castle
ActiveRecord
FluentNH
Lambda
Extensions
Castle NH
Facility
NH Prof
Castle
ActiveWriter
NH Proxy Gen
NHContrib
External
NHibernate Core
Relational Data Sources
Non-Relational Data Sources
NHSpatial
JetDriver
NHSearch
NHibernate
Core
Lambda
Extensions
NH Validator
Rhino Tools
NH LINQ
NH Attribute
Mapping
Castle
ActiveRecord
uNHAddins
NHBurrow
FluentNH
Mapping, Configuration, and Query
Castle NH
Facility
NH Caches
Infrastructure and Frameworks
NHibernate Implementation Framework (plus a lot more)
A Complete Infrastructure Stack
Unit-of-Work Abstraction
 IoC 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(DetachedCriteria criteria);
T Create();
DetachedCriteria CreateDetachedCriteria();
DetachedCriteria CreateDetachedCriteria(string alias);
void Delete(T entity);
void DeleteAll();
void DeleteAll(DetachedCriteria where);
object ExecuteStoredProcedure(string sp_name, params Parameter[] parameters);
ICollection<T2> ExecuteStoredProcedure<T2>(Converter<IDataReader, T2> converter, string sp_name, params Parameter[]
parameters);
bool Exists();
bool Exists(DetachedCriteria criteria);
ICollection<T> FindAll(params ICriterion[] criteria);
ICollection<T> FindAll(Order order, params ICriterion[] criteria);
ICollection<T> FindAll(Order[] orders, params ICriterion[] criteria);
ICollection<T> FindAll(DetachedCriteria criteria, params Order[] orders);
ICollection<T> FindAll(string namedQuery, params Parameter[] parameters);
ICollection<T> FindAll(int firstResult, int numberOfResults, params ICriterion[] criteria);
ICollection<T> FindAll(DetachedCriteria criteria, int firstResult, int maxResults, params Order[] orders);
ICollection<T> FindAll(int firstResult, int numberOfResults, Order selectionOrder, params ICriterion[] criteria);
ICollection<T> FindAll(int firstResult, int numberOfResults, string namedQuery, params Parameter[] parameters);
ICollection<T> FindAll(int firstResult, int numberOfResults, Order[] selectionOrder, params ICriterion[] criteria);
T FindFirst(params Order[] orders);
T FindFirst(DetachedCriteria criteria, params Order[] orders);
T FindOne(params ICriterion[] criteria);
T FindOne(DetachedCriteria criteria);
T FindOne(string namedQuery, params Parameter[] parameters);
Abstractions, Tools, and a WHOLE lot more!
uNhAddins: a Smörgåsbord!
NH UserTypes
NH Session
Mgt for WCF
NH Session
Mgt for WPF
IoC Container
Abstraction
Castle
Windsor
Adapter
Inflector
NH Audit Event
Listeners
Spring.NET
Adapter
Ninject
Adapter
Query
Pagination
NH Event
Listeners
ConversationPer-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
Cache Providers

MemCache
 Implementation for MemCached
 http://memcached.googlecode.com

Prevalence
 Bamboo.Prevalence engine
 http://bbooprevalence.sourceforge.net

SharedCache
 Inspired by MemCached but 100% managed code (C#)
 http://www.sharedcache.com

Velocity
 Microsoft’s Distributed Caching Engine (CTP2)

SysCache
 ASP.NET Cache Provider

SysCache2
 ASP.NET Cache Provider
○ with SQLServer call-back-invalidate support
Simpler Data Access
ActiveRecord Example
[ActiveRecord]
public class Category : ActiveRecordBase
{
[PrimaryKey]
public int Id { get; set; }
[Property]
public string Name { get; set; }
[BelongsTo("parent_id")]
public Category Parent { get; set; }
[HasMany]
public IList<Category> SubCategories { get; set; }
}
Integrated Validation Framework
Using NHValidator
Get and Build it (NHContrib)
Add References
Register Event Listeners
1.
2.
3.

4.
in code or hibernate.cfg.xml file
Off and Running!
Let’s Look at Some Code!
Death to String-Literals!!!!
Using NHLambdaExtensions
1.
2.
Download the Assembly (googlecode)
Add Reference to Assembly
Off and Running!
LambdaExtensions In Action
session.CreateCriteria<Customer>()
.Add(Restrictions.Eq(“Firstname”, “Steve”)
.List<Customer>();
session.CreateCriteria<Customer>()
.Add<Customer>(c => c.Firstname == “Steve”)
.List<Customer>();
One Query Language to Rule Them All!
Using NHLINQ
Download the Assembly (sourceforge)
1.

v1.0  NH 2.1GA release
Add Reference to Assembly
3. Off and Running!
2.
NHLINQ in Action
using (var session = sessionFactory.OpenSession())
{
using (var tx = session.BeginTransaction())
{
var customers = session.Linq<Customer>()
.Where(c => c.Firstname == “Steve”);
foreach (var customer in customers)
{
Console.WriteLine(customer.Firstname);
}
tx.Commit();
}
}
Stateful NHibernate Session Management for ASP.NET WebForms
Using Burrow
1.
2.
3.
4.
Get it and Build it (NHContrib)
Add References
Add NHibernate.Burrow config section
to web.config
Add Burrow HTTP Module to your
web.config
Modify web.config for Burrow
<configSections>
<section name="NHibernate.Burrow“
type="NHibernate.Burrow.Configuration.Nhibern
ateBurrowCfgSection, NHibernate.Burrow" />
</configSections>
<NHibernate.Burrow>
<persistenceUnits>
<add name="PersistenceUnit1" nh-config-file =
“~/hibernate.cfg.xml“ />
</persistenceUnits>
</NHibernate.Burrow>
Register Burrow HTTPModule
<httpModules>
<add name="NHibernate.Burrow.WebUtil.HttpModule”
type="NHibernate.Burrow.WebUtil.WebUtilHTTPModule
,NHibernate.Burrow.WebUtil"/>
</httpModules>
Burrow Conversation Pattern
BurrowFramework bf = new BurrowFramework();
bf.CurrentConversation.SpanWithPostBacks(TransactionStrat
egy.BusinessTransaction);
//do a bunch of work in a bunch of postbacks
BurrowFramework bf = new BurrowFramework();
bf.CurrentConversation.FinishSpan(); //commit to DB…
bf.CurrentConversation.GiveUp(); //…or abandon!
Spatial Queries
Understanding Spatial Data
Latitude / Longitude
Coordinate Systems (Spatial Reference ID)
SRID Projections
Supported Spatial Engines

MS SQLServer 2008
 Includes SQLServer 2008 Express!
MySQL
 PostGIS (PostGre-based)
 Oracle (work-in-progress)

Using NH Spatial
Get and Build it (NHContrib)
2. Add References (GeoAPI, Spatial, etc.)
3. Change Dialect in hibernate.cfg.xml
4. Optional: add support for spatial metadata
to the Configuration instance before
building SessionFactory
5. Map properties as ‘Geometry Type’
6. Off and Running!
1.
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.SqlClientDriver</property>
<property name="connection.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.MsSql2008SpatialDialect, NHibernate.Spatial.MsSql2008
</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.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory,NHibernate.ByteCode.LinFu
</property>
</session-factory>
</hibernate-configuration>
Add Spatial Metadata Classes
Configuration cfg = new Configuration();
cfg.Configure();
Metadata.AddMapping(cfg,
MetadataClass.GeometryColumn);
Metadata.AddMapping(cfg,
MetadataClass.SpatialReferenceSystem);
var sessionFactory =
cfg.BuildSessionFactory();
//rest of your app here!
Add Geometry Type + Mapping
using GeoAPI.Geometries
public class MyThing
{
public virtual IGeometry Geometry {get;set;}
//more of our class
}
<!-- short version -->
<property name="Geometry" column="the_geom" type =
"NHibernate.Spatial.Type.GeometryType, NHibernate.Spatial" />
<!-- long version -->
<property name="Geometry" column="the_geom">
<type name = "NHibernate.Spatial.Type.GeometryType,
NHibernate.Spatial">
<param name="srid">4326</param>
<param name="subtype">POLYGON</param>
</type>
</property>
Perform Spatial Queries
var country = session.CreateCriteria<Country>()
.Add(SpatialExpression.Contains("Boundaries", new
Point(-70.40, -33.24)))
.UniqueResult<Country>();
IList<Town> towns = session.CreateCriteria<Town>()
.Add(SpatialExpression.Filter("Boundaries", new
Envelope(-70, -68, -32, -34)))
.Add(Restrictions.Not(SpatialExpression.Contains("Bounda
ries", new Point(-70.40, -33.24))))
.List<Town>();
Querying Unstructured Text Indices
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.SqlClientDriver</property>
<property name="connection.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.MsSql2000Dialect</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.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory,NHibernate.ByteCode.LinFu
</property>
<property name=“hibernate.search.default.directory_provider”>
NHibernate.Search.Store.FSDirectoryProvider, NHibernate.Search
</property>
<property name=“hibernate.search.default.indexBase”>c:\MyIndex</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.FullTextIndexEventListener,
NHibernate.Search” type=“post-insert”/>
<listener class =
“NHibernate.Search.Event.FullTextIndexEventListener,
NHibernate.Search” type=“post-update”/>
<listener class =
“NHibernate.Search.Event.FullTextIndexEventListener,
NHibernate.Search” type=“post-delete”/>
//register in code
var cfg = new Configuration();
cfg.SetListener(NHibernate.Event.ListenerType.PostUpdate, new
FullTextIndexEventListener());
cfg.SetListener(NHibernate.Event.ListenerType.PostInsert, new
FullTextIndexEventListener());
cfg.SetListener(NHibernate.Event.ListenerType.PostDelete, new
FullTextIndexEventListener());
Add Attributes for Index Engine
public class Document
{
[DocumentId]
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 = sessionFactory.OpenSession())
{
using(var textsearch =
Search.CreateFullTextSession(session))
{
using (var tx = session.BeginTransaction())
{
var results = textsearch
.CreateFullTextQuery<Document>(“Title:Oredev")
.SetMaxResults(10)
.List<Document>();
}
}
}
Mapping and Configuration without XML
Using FluentNHibernate
1.
2.
3.
Get it ( http://fluentnhibernate.org )
Add References
Off and Running!
Sample Classes
XML Mappings
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="FluentNHibernateDemo"
namespace="FluentNHibernateDemo" >
<class name="Customer">
<id name="Id" column="CustomerId" 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="CustomerId"/>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
Fluent Mappings
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(c => c.Id).Column("CustomerId");
Map(c => c.Firstname);
Map(c => c.Lastname);
HasMany<Order>(c => c.Orders)
.Table("Order")
.KeyColumn("CustomerId")
.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.SqlClientDriver</property
>
<property name="connection.connection_string">
Server=(local)\sqlserver2005;initial
catalog=FluentNHibernateDemo;user=sa;password=password
</property>
<property name="adonet.batch_size">10</property>
<property name="show_sql">true</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</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.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryF
actory, NHibernate.ByteCode.Castle</property>
<mapping assembly="FluentNHibernateDemo"/>
</session-factory>
</hibernate-configuration>
Fluent Configuration
sessionFactory = Fluently.Configure()
.Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.Ms
Sql2005.ConnectionString(CONNSTRING)
.AdoNetBatchSize(10)
.ProxyFactoryFactory
<NHibernate.ByteCode.Castle.ProxyFactoryFactory>()
.UseOuterJoin())
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<CustomerMap>())
.BuildSessionFactory();
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
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

uNhAddins
 http://uNhAddins.googlecode.com

NHProf
 http://www.nhprof.com

HornGet.NET
 http://www.hornget.net
~fini~