NHibernate 3.0: Working with the Data Access Layer

Exclusive offer: get 50% off this eBook here
NHibernate 3.0 Cookbook

NHibernate 3.0 Cookbook — Save 50%

Get solutions to common NHibernate problems to develop high-quality performance-critical data access applications

€20.99    €10.50
by Jason Dentler | October 2010 | .NET Cookbooks Open Source Web Development

This article series by Jason Dentler, author of NHibernate 3.0 Cookbook, shows how to build a flexible, extensible data access layer based on NHibernate and its many query APIs. There are two styles of data access layer common in today's applications. The first recipe shows the beginnings of a typical data access object. The remaining recipes show how to set up a repository-based data access layer with NHibernate's various APIs.

In these articles we will cover the following topics:

  • Transaction Auto-wrapping for the data access layer
  • Setting up an NHibernate repository
  • Using Named Queries in the data access layer
  • Using ICriteria in the data access layer
  • Using Paged Queries in the data access layer
  • Using LINQ specifications in the data access layer

Of these the first two are dealt with in this article.

 

NHibernate 3.0 Cookbook

NHibernate 3.0 Cookbook

Get solutions to common NHibernate problems to develop high-quality performance-critical data access applications

  • Master the full range of NHibernate features
  • Reduce hours of application development time and get better application architecture and performance
  • Create, maintain, and update your database structure automatically with the help of NHibernate
  • Written and tested for NHibernate 3.0 with input from the development team distilled in to easily accessible concepts and examples
  • Part of Packt's Cookbook series: each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible
        Read more about this book      

(For more resources on NHibernate, see here.)

Transaction Auto-wrapping for the data access layer

This article by Jason Dentler, author of NHibernate 3.0 Cookbook, shows how we can set up the data access layer to wrap all data access in NHibernate transactions automatically.

Getting ready

Complete the Eg.Core model and mappings. Download code (ch:1)

How to do it...

  1. Create a new class library named Eg.Core.Data.
  2. Add a reference to NHibernate.dll and the Eg.Core project.
  3. Add the following two DAO classes:

    public class DataAccessObject<T, TId>
    where T : Entity<TId>
    {

    private readonly ISessionFactory _sessionFactory;

    private ISession session
    {
    get
    {
    return _sessionFactory.GetCurrentSession();
    }
    }
    public DataAccessObject(ISessionFactory sessionFactory)
    {
    _sessionFactory = sessionFactory;
    }

    public T Get(TId id)
    {
    return Transact(() => session.Get<T>(id));
    }

    public T Load(TId id)
    {
    return Transact(() => session.Load<T>(id));
    }

    public void Save(T entity)
    {
    Transact(() => session.SaveOrUpdate(entity));
    }

    public void Delete(T entity)
    {
    Transact(() => session.Delete(entity));
    }

    private TResult Transact<TResult>(Func<TResult> func)
    {
    if (!session.Transaction.IsActive)
    {
    // Wrap in transaction
    TResult result;
    using (var tx = session.BeginTransaction())
    {
    result = func.Invoke();
    tx.Commit();
    }
    return result;
    }
    // Don't wrap;
    return func.Invoke();
    }

    private void Transact(Action action)
    {
    Transact<bool>(() =>
    {
    action.Invoke();
    return false;
    });
    }
    }
    public class DataAccessObject<T>
    : DataAccessObject<T, Guid>
    where T : Entity
    {
    }

How it works...

NHibernate requires that all data access occurs inside an NHibernate transaction and this can be easily accomplished with AOP.

Remember, the ambient transaction created by TransactionScope is not a substitute for a NHibernate transaction.

This recipe shows a more explicit approach. To ensure that at least all our data access layer calls are wrapped in transactions, we create a private Transact function that accepts a delegate, consisting of some data access methods, such as session.Save or session.Get. This Transact function first checks if the session has an active transaction. If it does, Transact simply invokes the delegate. If it doesn't, it creates an explicit NHibernate transaction, then invokes the delegate, and finally commits the transaction. If the data access method throws an exception, the transaction will be rolled back automatically as the exception bubbles up through the using block.

There's more...

This transactional auto-wrapping can also be set up using SessionWrapper from the unofficial NHibernate AddIns project at http://code.google.com/p/unhaddins. This class wraps a standard NHibernate session. By default, it will throw an exception when the session is used without an NHibernate transaction. However, it can be configured to check for and create a transaction automatically, much in the same way I've shown you here.

See also

  • Setting up an NHibernate repository
NHibernate 3.0 Cookbook Get solutions to common NHibernate problems to develop high-quality performance-critical data access applications
Published: October 2010
eBook Price: €20.99
Book Price: €34.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on NHibernate, see here.)

Setting up an NHibernate Repository

Many developers prefer the repository pattern over data access objects. In this recipe, I'll show you how to set up the repository pattern with NHibernate.

Getting ready

Set up the Eg.Core project with the model and mappings. Download code (ch:1)

How to do it...

  1. Create a new, empty class library project named Eg.Core.Data.
  2. Add a reference to Eg.Core project
  3. Add the following IRepository interface:

    public interface IRepository<T>: IEnumerable<T>
    where T : Entity
    {
    void Add(T item);
    bool Contains(T item);
    int Count { get; }
    bool Remove(T item);
    }

  4. Create a new, empty class library project named Eg.Core.Data.Impl.
  5. Add references to Eg.Core and Eg.Core.Data
  6. Add a new abstract class named NHibernateBase using the following code:

    protected readonly ISessionFactory _sessionFactory;

    protected virtual ISession session
    {
    get
    {
    return _sessionFactory.GetCurrentSession();
    }
    }

    public NHibernateBase(ISessionFactory sessionFactory)
    {
    _sessionFactory = sessionFactory;
    }

    protected virtual TResult Transact<TResult>(
    Func<TResult> func)
    {
    if (!session.Transaction.IsActive)
    {
    // Wrap in transaction
    TResult result;
    using (var tx = session.BeginTransaction())
    {
    result = func.Invoke();
    tx.Commit();
    }
    return result;
    }
    // Don't wrap;
    return func.Invoke();
    }

    protected virtual void Transact(Action action)
    {
    Transact<bool>(() =>
    {
    action.Invoke();
    return false;
    });
    }

  7. Add a new class named NHibernateRepository using the following code:

    public class NHibernateRepository<T> :
    NHibernateBase,
    IRepository<T> where T : Entity
    {
    public NHibernateRepository(ISessionFactory sessionFactory)
    : base(sessionFactory)
    {
    }

    public void Add(T item)
    {
    Transact(() => session.Save(item));
    }

    public bool Contains(T item)
    {
    if (item.Id == default(Guid))
    return false;
    return Transact(() => session.Get<T>(item.Id)) != null;
    }

    public int Count
    {
    get
    {
    return Transact(() => session.Query<T>().Count());
    }
    }

    public bool Remove(T item)
    {
    Transact(() => session.Delete(item));
    return true;
    }

    public IEnumerator<T> GetEnumerator()
    {
    return Transact(() => session.Query<T>()
    .Take(1000).GetEnumerator());
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
    return Transact(() => GetEnumerator());
    }
    }

How it works...

The repository pattern, as explained in http://martinfowler.com/eaaCatalog/repository.htm, has two key features:

  • It behaves as an in-memory collection
  • Query specifications are submitted to the repository for satisfaction.

In this recipe, we are concerned only with the first feature, behaving as an in-memory collection. The remaining recipes in this article will build on this base, and show various methods for satisfying the second point.

Because our repository should act like an in-memory collection, it makes sense that our IRepository<T> interface should resemble ICollection<T>.

Our NHibernateBase class provides both contextual session management and the automatic transaction wrapping explained in the previous recipe.

NHibernateRepository simply implements the members of IRepository<T>.

There's more...

The Repository pattern reduces data access to its absolute simplest form, but this simplification comes with a price. We lose much of the power of NHibernate behind an abstraction layer. Our application must either do without even basic session methods like Merge, Refresh, and Load, or allow them to leak through the abstraction.

See also

  • Transaction Auto-wrapping for the data access layer
  • Using Named Queries in the data access layer
  • Using ICriteria in the data access layer
  • Using Paged Queries in the data access layer
  • Using LINQ specifications in the data access layer

Summary

In this article we covered:

  • Transaction Auto-wrapping for the data access layer
  • Setting up an NHibernate repository

In the next article we will cover Using Named Queries in the data access layer.


Further resources on this subject:


NHibernate 3.0 Cookbook Get solutions to common NHibernate problems to develop high-quality performance-critical data access applications
Published: October 2010
eBook Price: €20.99
Book Price: €34.99
See more
Select your format and quantity:

About the Author :


Jason Dentler

Jason Dentler grew up in the small Texas town of Mission Valley. He started tinkering with computers as a kid in the late 1980s, and all these years later, he hasn't stopped. He's worked in a few different industries. Currently, he builds really awesome software in higher education. He's an Eagle Scout and a graduate of the University of Houston – Victoria.

Books From Packt


NHibernate 2 Beginner's Guide
NHibernate 2 Beginner's Guide

WCF 4.0 Multi-tier Services Development with LINQ to Entities
WCF 4.0 Multi-tier Services Development with LINQ to Entities

ASP.NET 3.5 Application Architecture and Design
ASP.NET 3.5 Application Architecture and Design

Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications
Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications

.NET Compact Framework 3.5 Data Driven Applications
.NET Compact Framework 3.5 Data Driven Applications

Microsoft Azure: Enterprise Application Development
Microsoft Azure: Enterprise Application Development

Applied Architecture Patterns on the Microsoft Platform
Applied Architecture Patterns on the Microsoft Platform

Microsoft Windows Workflow Foundation 4.0 Cookbook
Microsoft Windows Workflow Foundation 4.0 Cookbook


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software