1

1) What is more appropriate/commonly used approach for concurrency control? Pessimistic or optimistic locking?

2) How do I notify a user if there's a lock on an item or whether rollback had occured?

3) Suppose I've added all needed markup (like optimistic-locking="false" to exclude properties I don't want to be involved in comparing) to my entity mapping files and defined a Version property on entity classes to handle concurrency control. Would that be enough and all stuff is processed within/by NHibernate. Or additional modifiactions should be present? For example in Repository?

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();
        }
    }
}

// DI
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<>));
    }
}

I'm using a long session with multiple transactions.

Thanks!

lexeme
  • 2,915
  • 10
  • 60
  • 125

2 Answers2

1

Your repository should never handle transaction scopes. Its a totally different requirement and Repository cant know what boundaries should transaction be have.

Transactions should be handled somewhere outside by infrastructure code. If you are using ASP.NET MVC - action filters are appropriate(see implementation is Sharp Architecture project).

If its ASP.NET then module or global asax handling could be applied.

But just DON'T handle it in repository, its very leaky abstraction, you WILL need expose boundaries to caller.

Sly
  • 15,046
  • 12
  • 60
  • 89
  • Ok. I've made a search on why this is a bad practice to expose transactions on repository. So now I have two questions. I want my `session-per-request` scheme to stay. What issues should I consider if logics stays the same? And second. There are tons of approaches to implement either action filter-based transaction handling or something else. But most of them are disputable and not clear at all. Could you then give-me/point-at a consistent explanation. Thanks a lot! – lexeme Feb 24 '12 at 09:11
  • Just look here https://github.com/sharparchitecture/Sharp-Architecture/tree/master/Solutions/SharpArch.NHibernate Its probably best direction – Sly Feb 24 '12 at 10:13
  • I've looked about it. Thanks. But I'm still curious in issues that are provided with solution that I've got. What problems will I face e.g. incorrect writing to a database or whatsoever? Could you help me? I'm asking since I have nearly built a project, possibly with the mistake in data access strategy implementation. – lexeme Feb 24 '12 at 11:10
  • your implementation clearly states strategy "last one wins" so only issue you can have is that changes of one person will be overridden by other, but you will get same results in other case. if you are nearly implemented everything and didn't have any problems in testing, I don't think you will have them in production... but who knows that for sure? :) – Sly Feb 24 '12 at 12:12
  • And what if I refactor `Repository` with `StaleObjectStateException cathcing` on modifictaion queries and give it (at the moment I don't know what's the better one) a proper isolation level. I'm already using versioning on my entities. – lexeme Feb 24 '12 at 12:33
0

You are missing the "unit of work" pattern here.

VahidN
  • 18,457
  • 8
  • 73
  • 117