5

I am wondering how much should my service layer know of my repository? In past project I always returned lists and had a method for each thing I needed.

So if I needed to return all rows that had an Id of 5 that would be a method. I do have generic repository for create, update, delete and other NHibernate options but for querying I don't.

Now I am starting to use more IQueryable as I started to run into problems of having so many methods for each case.

Say if I needed to return all that had a certain Id and needed 3 tables that where eager loaded this would be a new method. If I needed a certain Id and no eager loading that would be a separate method.

So now I am thinking if I method that does the where clause part and return IQueryable then I can add on the result (i.e. if I need to do eager loading).

At the same time though this now makes the service layer more aware of the repository layer and I no longer can switch out the repository as easy as now I have specific NHibernate in the service layer.

I am also not sure how that would effect mocking.

So now I am wondering if I go down this route if the repository is needed as it now seems like they have been blended together.

Edit

If I get rid of my repository and just have the session in my service layer is there a point to having a unit of work class then?

public class UnitOfWork : IUnitOfWork, IDisposable
    {
        private ITransaction transaction;
        private readonly ISession session;

        public UnitOfWork(ISession session)
        {
            this.session = session;
            session.FlushMode = FlushMode.Auto;
        }

        /// <summary>
        /// Starts a transaction with the database. Uses IsolationLevel.ReadCommitted
        /// </summary>
        public void BeginTransaction()
        {
            transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
        }

        /// <summary>
        /// starts a transaction with the database.
        /// </summary>
        /// <param name="level">IsolationLevel the transaction should run in.</param>
        public void BeginTransaction(IsolationLevel level)
        {
            transaction = session.BeginTransaction(level);
        }

        private bool IsTransactionActive()
        {
            return transaction.IsActive;
        }

        /// <summary>
        /// Commits the transaction and writes to the database.
        /// </summary>
        public void Commit()
        {
            // make sure a transaction was started before we try to commit.
            if (!IsTransactionActive())
            {
                throw new InvalidOperationException("Oops! We don't have an active transaction. Did a rollback occur before this commit was triggered: "
                                                            + transaction.WasRolledBack + " did a commit happen before this commit: " + transaction.WasCommitted);
            }

            transaction.Commit();
        }

        /// <summary>
        /// Rollback any writes to the databases.
        /// </summary>
        public void Rollback()
        {
            if (IsTransactionActive())
            {
                transaction.Rollback();
            }
        }

        public void Dispose() // don't know where to call this to see if it will solve my problem
        {
            if (session.IsOpen)
            {
                session.Close();
            }

        }
chobo2
  • 83,322
  • 195
  • 530
  • 832

2 Answers2

4

Everyone has an opinion how to use the repository, what to abstract etc. Ayende Rahien has got few good posts about the issue: Architecting in the pit of doom: The evils of the repository abstraction layer and Repository is the new Singleton. Those give you some pretty good reasons why you shouldn't try to create yet another abstraction on top of NHibernate's ISession.

Toni Parviainen
  • 2,217
  • 1
  • 16
  • 15
  • I will look more into it. The thing that gets me is I like the idea that the service layer does not know anything about the database making it easy to unit test(if I ever need to) and easy to switch out ORMs. how do you handle these scenarios? – chobo2 Jan 02 '12 at 22:15
  • I am also wondering if I get rid of the repositories is there a point to my unit of work class then? See Edit – chobo2 Jan 02 '12 at 23:14
  • You can use the UnitOfWork just to wrap the session, or even use the NH session directly. As for unit testing, you can use an in-memory database for unit testing **with** NHiberate. Here's a post about it from Ayende: http://ayende.com/blog/3983/nhibernate-unit-testing – Ilya Kogan Jan 03 '12 at 06:27
  • @chobo2 There is no easy way to switch out ORMs. If you take NHibernate you want to use caching, batch operations, future queries etc. Some (or even all) of those things are not available in some other ORM (like EntityFramework). If you want to have abstraction so that you can switch from NH to EF then you cannot use those NH specific features. Also the ISession is already an abstraction. If you put your complex queries inside their own classes then you have lot of abstraction and you can still use all of the feature NHibernate provides. – Toni Parviainen Jan 03 '12 at 13:10
  • @IlyaKogan - what gain would you have from wrapping the unit of work over just using, using statements for the transactions if everything is in the same class. – chobo2 Jan 03 '12 at 16:53
  • @ToniParviainen - I guess that's what made the repository pattern so appealing and most books that talk about the repository pattern(asp.net mvc book). Mostly leave out this problem. If I move the complex queries out is that not almost like a repository then? – chobo2 Jan 03 '12 at 16:54
  • No, if you move the queries to the business logic, they will be part of the business processes. This is very different from a repository. – Ilya Kogan Jan 03 '12 at 18:04
  • @IlyaKogan I am talking about ToniParviainen comment about making the complex queries into their own class not the simple queries what would become part of the business processes as you stated. – chobo2 Jan 03 '12 at 18:50
  • @ToniParviainen - if I don't use the repository pattern should I just use using statements instead of my unit of work class? – chobo2 Jan 04 '12 at 17:51
  • chobo2 I usually use something like [TransactionBoundary](http://pastebin.com/nzpYXVti) which takes care of handling the transaction. This assumes that the ISession has already been opened. By using the using statement I don't have to care about possible exceptions since transaction is rolled back automatically – Toni Parviainen Jan 05 '12 at 13:28
2

The thing about NHibernate is that it gives you the most if you don't try to abstract it out. Making your service layer depend on NHibernate is not necessarily a bad thing. It gives you control over sessions, caching and other NHibernate features, and thus enables you to imporove performance, not to mention saving you from all the redundant wrapping code that you've mentioned.

Ilya Kogan
  • 21,995
  • 15
  • 85
  • 141
  • 1
    Adding to this answer: The NHibernate Session IS the UnitOfWork – Ivo Jan 02 '12 at 23:36
  • 1
    That is why I am wondering if there is a point to the UnitOfWork class I made if I am not using the repository pattern? – chobo2 Jan 03 '12 at 18:50