views:

81

answers:

3

Hey all..

I am looking to get some feedback on how I can improve my design. Specifically, I don't want to have to create a new repository object for each of my domain objects but I also do not want to rewrite the Session and Transaction logic over and over.

To alleviate the need to write the code to obtain a new session and transation for every database transaction I make I created and generic abstract class that looks like this:

 public class AbstractNHibernate<T> where T : class
{

    public void Add<T>(T entity) 
    { 
        using(ISession session = NHibernateHelper.OpenSession())
        using (ITransaction transaction = session.BeginTransaction())
        {
            session.Save(entity);
            transaction.Commit();
        }
    }
}

Thats great but then I have to create a repository for each of my domain entities like so:

    public class ConnectionModel : AbstractNHibernate<Connection>
    {
        public void SaveConnection(Connection conn)
{
Add(conn);
}
    }

I could potentially have many of these. Can someone suggest a different approach?

Thanks in advance.

A: 

The way which I have seen this done (and how I do this) is to establish an interface, Create a Nhiberate class which realises this interface (Repository Pattern)

http://www.rosscode.com/blog/index.php?title=the_repository_pattern_andash_iarsquo_m_&amp;more=1&amp;c=1&amp;tb=1&amp;pb=1

also the use of the Specification pattern allows for queries to be passed to the repository. more information can be found here:

http://www.mostlyclean.com/category/NHibernate.aspx

things to note is the session is created elsewhere and then injected (passed) into the repositories, I use an IoC container such as Windsor to do this.

HTH

dbones
+1  A: 

Your repositories should (in general) not open sessions or perform transactions. That should be done in a service layer or the UI. With your current design there's no way to have multiple repositories participate in the same transaction. You can accomplsh this by requiring the ISession in the repository constructor.

I also dislike the one repository per object model, a better approach is to logically group together common repository functions. For example, a CompanyRepository would have methods for working with companies and related data -- CompanyType, CompanyStatus, etc.

Jamie Ide
A: 

Maybe I am not understanding your question? You seem to be asking more about how to implement the generics so you do not have to create a type specific class for each object rather than asking an nhibernate question.

Here is a simple Repository that accepts any type T. You just remove the T from the class signature and instantiate. But keep in mind this is little more than a session wrapper, more a Unit of work than a repository. Implementing queries will require some work to try to make generic. You could use something like this as a base class for a subtype where you need complex queries and also as a standalone instance if you only support very basic queries for other objects.

/// <summary>
/// Repository defines simple class with standard methods
/// to accept and operate on any type.
/// </summary>
public class Repository
{
    private ISession _session;

    public ISession Session
    {
        get { return _session; }
    }


    /// <summary>
    /// Save an entity.
    /// </summary>
    public void Save<T>(T entity)
    {
        Reconnect(_session);
        try
        {
            _session.Save(entity);
        }
        finally
        {
            Disconnect(_session);
        }
    }

    /// <summary>
    /// Update an entity
    /// </summary>
    public void Update<T>(T entity)
    {
        Reconnect(_session);
        try
        {
            _session.Update(entity);
        }
        finally
        {
            Disconnect(_session);
        }
    }

    /// <summary>
    /// Delete an entity
    /// </summary>
    public void Delete<T>(T entity)
    {
        Reconnect(_session);
        try
        {
            _session.Delete(entity);
        }
        finally
        {
            Disconnect(_session);
        }
    }

    /// <summary>
    /// Retrieve an entity
    /// </summary>
    public T GetById<T>(Guid id)
    {
        Reconnect(_session);
        try
        {
            return _session.Get<T>(id);
        }
        finally
        {
            Disconnect(_session);
        }
    }

    /// <summary>
    /// Method for flushing the session.
    /// </summary>
    public void Flush()
    {
        Reconnect(_session);
        try
        {
            _session.Flush();
            _session.Clear();
        }
        finally
        {
            Disconnect(_session);
        }
    }

    /// <summary>
    /// Reconnect to the session. Accept parameter so we can use anywhere.
    /// </summary>
    public void Reconnect(ISession session)
    {
        if (!session.IsConnected)
        {
            session.Reconnect();
        }
    }

    /// <summary>
    /// Disconnect from the session.  Accept parameter so we can use anywhere.
    /// </summary>
    public void Disconnect(ISession session)
    {
        if (session.IsConnected)
        {
            session.Disconnect();
        }
    }

    public Repository(ISession session)
    {
        _session = session;
    }

}

}

Sisyphus
why all the session reconnects and disconnects?
dbones
I had the same question as dbones.
Nick
No good reason. Immediate and explicit disconnects and reconnects around every action are a policy requirement that came from a DBA who is very anti-ORM and tried to squelch the whole concept. He was overruled on that but did have enough political clout to impose some (often absurd) rules on development. Sorry for any confusion, after a while it becomes habit to just do things this way.
Sisyphus
unlucky, does this not cause issues with transactions? As I would have thought they need to be committed before the disconnect. have a look at section 10.5 in the NH manual http://nhforge.org/doc/nh/en/index.html#transactions-disconnection
dbones