Generic DAO with NHibernate

4/28/06 Update: The NHibernate codeproject.com article wins ASP.NET article of the month. Woohoo!

3/14/06 Update: See how this is used in a sample application at http://www.codeproject.com/useritems/NHibernateBestPractices.asp.


Hibernate.org has a great article on creating a generic DAO for Hibernate in Java. Below is what I use for the C# port. 

The interface for common CRUD functionality...

public interface GenericDAO {

T GetById(IdDataType id, bool shouldLock);

List GetAll();

List GetByExample(T exampleInstance, string[] propertiesToExclude);

T SaveOrUpdate(T entity);

void Delete(T entity);

}

The generic DAO implementation...

public abstract class GenericNHibernateDAO : GenericDAO

{

/// Could be set using contruction injection IoC

public GenericNHibernateDAO(ISessionManager sessionManager) {

this.sessionManager = sessionManager;

}

public T GetById(IdDataType id, bool shouldLock) {

ISession session = GetSession();

T entity;

if (shouldLock) {

  entity = (T) session.Load(persitentType, id, LockMode.Upgrade);

}

else {

  entity = (T) session.Load(persitentType, id);

}

return entity;

}

public List GetAll() {

return GetByCriteria();

}

protected List GetByCriteria(params ICriterion[] criterion) {

ISession session = GetSession();

ICriteria criteria = session.CreateCriteria(persitentType);

foreach (ICriterion criterium in criterion) {

  criteria.Add(criterium);

}

GenericUtils genericUtils = new GenericUtils();

return genericUtils.ConvertToGenericList(criteria.List());

}

public List GetByExample(T exampleInstance, string[] propertiesToExclude) {

ISession session = GetSession();

ICriteria criteria = session.CreateCriteria(persitentType);

Example example = Example.Create(exampleInstance);

foreach (string propertyToExclude in propertiesToExclude) {

  example.ExcludeProperty(propertyToExclude);

}

criteria.Add(example);

GenericUtils genericUtils = new GenericUtils();

return genericUtils.ConvertToGenericList(criteria.List());

}

public T SaveOrUpdate(T entity) {

ISession session = GetSession();

session.SaveOrUpdate(entity);

return entity;

}

public void Delete(T entity) {

ISession session = GetSession();

session.Delete(entity);

}

private ISession GetSession() {

Check.Require(sessionManager != null, "sessionManager was not set");

return sessionManager.OpenSession();

}

private Type persitentType = typeof(T);

private ISessionManager sessionManager;

}

And for using this within your code...

public class ProjectDAONHibernate : GenericNHibernateDAO<Project, int> {

public ProjectDAONHibernate(ISessionManager sessionManager) : base(sessionManager) {}

}


Notes:

NHibernate Generics: To use generics with NHibernate, use the “NHibernate Generics” assembly available at http://www.ayende.com/projects/nhibernate-query-analyzer/generics.aspx.

SessionManager: To help with NHibernate session management, a good tool of choice is Castle Project's NHibernate facility:  http://www.castleproject.org/index.php/Facility:NHibernate.  Alternatively, a good design is explained in Chapter 8 of Hibernate In Action by Christian Bauer and Gavin King.  (They should be having a second edition coming out soon.)  The beneift of using Castle Project comes to light when used in conjunction with their Transaction factility; the Transaction facility allows you to mark which actions should be transactional via inline attributes.

Design by Contract:  You may have noticed Check.Require reference.  This is a completely optional, design-by-contract constraint using the VERY light weight framework described at http://www.codeproject.com/csharp/designbycontract.asp.

I've had wonderful success with NHibernate in the past and can continue to embrace it with C# 2.0 using generics.  The .NET community is finally starting to take notice of ORM tools like NHibernate which are helping to shave weeks, if not months, off of development.  I hope you all experience similar successes.

This article is part of the GWB Archives. Original Author: Billy McCafferty

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.