views:

122

answers:

3

Hi Guys, hows it going?

I'm in my first time with DDD, so I'm begginer! So, let's take it's very simple :D I developed an application using asp.net mvc 2 , ddd and nhibernate. I have a domain model in a class library, my repositories in another class library, and an asp.net mvc 2 application. My Repository base class, I have a construct that I inject and dependency (my unique ISessionFactory object started in global.asax), the code is:

public class Repository<T> : IRepository<T>
    where T : Entidade
{
    protected ISessionFactory SessionFactory { get; private set; }
    protected ISession Session
    {
        get { return SessionFactory.GetCurrentSession(); }
    }

    protected Repository(ISessionFactory sessionFactory)
    {
        SessionFactory = sessionFactory;
    }        

    public void Save(T entity)
    {
        Session.SaveOrUpdate(entity);
    }

    public void Delete(T entity)
    {
        Session.Delete(entity);
    }

    public T Get(long key)
    {
        return Session.Get<T>(key);
    }

    public IList<T> FindAll()
    {
        return Session.CreateCriteria(typeof(T)).SetCacheable(true).List<T>();
    }
}

And After I have the spefic repositories, like this:

public class DocumentRepository : Repository<Domain.Document>, IDocumentRepository
{
        // constructor
        public DocumentRepository (ISessionFactory sessionFactory) : base(sessionFactory) 
        { }

        public IList<Domain.Document> GetByType(int idType)
        {
            var result = Session.CreateQuery("from Document d where d.Type.Id = :IdType")
                .SetParameter("IdType", idType)
                .List<Domain.Document>();

            return result;
        }
}

there is not control of transaction in this code, and it's working fine, but, I would like to make something to control this repositories in my controller of asp.net mvc, something simple, like this:

using (var tx = /* what can I put here ? */) {
   try 
   {
     _repositoryA.Save(objA);
     _repositoryB.Save(objB);
     _repositotyC.Delete(objC);
     /* ... others tasks ... */

     tx.Commit();
   }
   catch
   {
     tx.RollBack();
   }
}

I've heared about NHibernateUnitOfWork, but i don't know :(, How Can I configure NHibernateUnitOfWork to work with my repositories ? Should I change the my simple repository ? Sugestions are welcome!

So, thanks if somebody read to here! If can help me, I appretiate!

PS: Sorry for my english!

bye =D

+2  A: 

Session is NHibernate's unit of work. But you can always create your own abstraction of it.

using (var tx = Session.BeginTransaction) { ...
epitka
Hi Eptitka, thanks! If I create a classe that acept an ISessionFactory (by injecting the dependency in contructor) and use GetCurrentSession to get a ISession and control the Transaction, is it in accordance with DDD ?
Felipe
Your classes should not be dependent on any services, repositories etc.
epitka
Felipe, the problem with this approach and with the one you detail above is that every call to the repository will result in a separate transaction. Either this or you have to inject the session into your repository. It is for this reason that one often sees a UnitOfWork implemented as a separate class that starts and stops once per session (per-page in asp.net), rather than relying on the ISession object provided by NHibernate
Jeffrey Cameron
+1  A: 

You can make the Session on your Repository a public property. Then you can do the following:

using(var tx = _repository.Session.BeginTransaction())

On a somewhat related note, this should all be inside of a service layer, not in your controller. Then the controller should have references to your services.

Keith Rousseau
Hi Keith, thanks man! I've heared about Service layer, and now I know how to implement it :D, thanks man!If I had some repositories and call BeginTransaction to get ITransaction (in GetCurrentSession of ISessionFactory injected by Unity), it will take a transaction in the two repositories like my sample above, all right ? using (var tx = _repository?(any repository).Session.BeginTransaction()) { _repositoryA.Save(objA); _repositoryB.Save(objB); _repositoryC.Delete(objC); tx.Commit();}Cheers
Felipe
Keith, problem with that is you now have a dependency on your ORM (NHibernate). This may or may not be an issue depending on how far you want to take the Decoupling/SOLID thing. If you were taking it all the way, then you'd want your Repository to return some form of Interface for handling transactions, injecting in an NHibernate implementation behind the scenes eg. using(ITransaction tx = _repository.StartTransaction())
Sunday Ironfoot
@Sunday - I agree that in order to fully decouple my service layer from NHibernate I would need to do that, but my service layer is already fairly tightly coupled to NH because of criteria. My service layer prepares the criteria and issues them against generic repositories and criteria are very NH specific. I'm perfectly ok with this coupling for my needs, as I don't see myself pulling out NH anytime soon.
Keith Rousseau
+1  A: 

There is an excellent library called NCommon (source) that provides a great UnitOfWork implementation built right in. Version 1.1 allows you to do something like:

public class Foo
{
    private readonly IRepository<Stuff> _repository;

    public Foo(IRepository<Stuff> repository)
    {
         _repository = repository;
    }

    public void DoSomething()
    {
        using (var scope = new UnitOfWorkScope())
        {
           _repository.Save(a);
           scope.Commit();
        }
    }
}

It integrates with the latest NHibernate and even uses NHibernate.Linq to provide some powerful querying features. You have little or nothing to build yourself and it works great out of the box.

Edit:

I elaborated on my example to show the full recommended way to use NCommon in a project with dependency-injection.

Jeffrey Cameron
Hi Jeff, thanks man! I've heared about NCommon, but i'd like to know, Need I do a configuration or initialization of UnitOfWorkScope in my global.asax or something like that Or I just need to reference in my project and use with my repository (like the code above) ?
Felipe
You do need to do some simple configuration (in global.asax if this is a web app) to tell NCommon what sort of UnitOfWorkScope to use. You can then use the CommonServiceLocator (or your own kernel) to get an instance of a repository. There is an excellent blog posting from the author of NCommon on this here: http://www.codeinsanity.com/2010/04/unit-of-work-implementation-in-ncommon.html
Jeffrey Cameron