1

So at the moment I have such a repository implementation:

public class Repository<T> : IRepository<T> where T : AbstractEntity<T>, IAggregateRoot
{
    private ISession session;

    public Repository(ISession session)
    {
        this.session = session;
    }

    public T Get(Guid id)
    {            
        return this.session.Get<T>(id);            
    }
    public IQueryable<T> Get(Expression<Func<T, Boolean>> predicate)
    {
        return this.session.Query<T>().Where(predicate);            
    }
    public IQueryable<T> Get()
    {
        return this.session.Query<T>();            
    }
    public T Load(Guid id)
    {
        return this.session.Load<T>(id);
    }
    public void Add(T entity)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Save(entity);
            transaction.Commit();
        }
    }
    public void Remove(T entity)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Delete(entity);
            transaction.Commit();
        }
    }
    public void Remove(Guid id)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Delete(this.session.Load<T>(id));
            transaction.Commit();
        }
    }
    public void Update(T entity)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Update(entity);
            transaction.Commit();
        }
    }
    public void Update(Guid id)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Update(this.session.Load<T>(id));
            transaction.Commit();
        }
    }
}

Then I use Ninject module like this.

public class DataAccessModule : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        this.Bind<ISessionFactory>()
            .ToMethod(c => new Configuration().Configure().BuildSessionFactory())
            .InSingletonScope();

        this.Bind<ISession>()
            .ToMethod(ctx => ctx.Kernel.TryGet<ISessionFactory>().OpenSession())
            .InRequestScope();

        this.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
    }
}

Schema export and update are called like a tests:

[TestFixture]
public class SchemaManipulations
{
    [Test]
    [Ignore]
    public void CreateDatabaseSchema()
    {
        new SchemaExport(new Configuration().Configure()).Create(false, true);
    }

    [Test]
    [Ignore]
    public void UpdateDatabaseSchema()
    {
        new SchemaUpdate(new Configuration().Configure()).Execute(false, true);
    }
}

I keep 'clean' my domain layer: validation logic is implemented with FluentValidation, it has no knowledge of NHibernate neither of anything else.

And that seemed perfect to me.. until I wondered how do I implement version concurrency. I choose to use optimistic-locking and as for mapping it correctly for NH it was not a problem. And I was needed to know how do transaction handle, how do I inform user while editing locked item?

So one more question appeared version concurrency control for a long session. NHibernate. ASP.NET MVC where it was said that exposing transaction on Repository is not recommended.

QUESTION ITSELF

I have already heard about SharpArchitecture and about UOW. And that's quite enough.

But I'm interested in issues provided with my solution of data access strategy: what errors/malfunctions will I face using it like that?

Also would it be a solution to use the proposed by Kaleb Pederson NHibernate, transactions and TransactionScope approach?

Thanks!

Community
  • 1
  • 1
lexeme
  • 2,915
  • 10
  • 60
  • 125
  • IN addition to the answer below, I would say don't use TransactionScope for a few reasons. The first is that it depends on the database data provider you are using as to whether it will work. So if you are only using SQL Server, it's probably OK. In addition, if you are sloppy and end up with multiple session/connections it will elevate the transaction to the DTC automatically, which you (probably) don't want. I would take a look at the Session per Request pattern. There are various implementations of this pattern, so I will leave it to you to determine the best one for you. – swannee Feb 24 '12 at 15:37

1 Answers1

1

how would you write code like this?

// Save both together or none of it
rep1.Save(newSomeEntity);
rep2.Save(SomeOtherEntity);

having it not inside repository is easy

var rep1 = new Repository<SomeEntity>(session);
var rep2 = new Repository<SomeOtherEntity>(session);
using (var tx = session.BeginTransaction())
{
    try
    {
        rep1.Save(newSomeEntity);
        rep2.Save(SomeOtherEntity);
        tx.Commit();
    }
    catch (SomeException ex)
    {
        Handle(ex);
        tx.RollBack();
    }
}
Firo
  • 30,626
  • 4
  • 55
  • 94
  • I would agree with this. The only think I do differently is I have my own IUow which has an NhUow implementation. The IUow exposes the transaction. The reason being that I don't want to reference Nhib directly in my code. So it's nice to abstract the NHIb session into your own Uow. – swannee Feb 24 '12 at 15:29
  • i did not know you have your own UOW. I just showed that there are scenarios which cant be done with the implementation in the question – Firo Feb 24 '12 at 17:01
  • Sure but you can reference the session/uow whatever both inside of the repository and outside of it. – swannee Feb 24 '12 at 17:11
  • Sorry to ask the obvious, but what is UOW? I have googled and followed the referenced SO article but cannot find what the acronym stands for...? – tinonetic Jan 16 '15 at 08:24
  • it means "unit of work" see http://martinfowler.com/eaaCatalog/unitOfWork.html NHibernate's ISession implements this pattern – Firo Jan 16 '15 at 08:57