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!
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.