I'm using the CQRS pattern to get the data from the DB using NHibernate.
Here is the CommittingTransactionCommandHandler which calls the UpdateProductHandler
class CommittingTransactionCommandHandler
{
private readonly ISession session;
private readonly ICommandHandler<TCommand> _inner; //Generic Command Handlers
public CommittingTransactionCommandHandler(ISession session)
{
this.session = session;
}
public async Task Execute(TCommand command)
{
using (var txn = session.BeginTransaction(IsolationLevel.Unspecified))
{
try
{
await _inner.Update(command); // This calls the UpdateProducthandler's Update method
txn.Commit();
}
catch (Exception ex)
{
throw;
}
}
}
}
Here is the Command Handler for the Update.
class UpdateProductHandler : ICommand
{
private readonly ISession session;
public UpdateProductHandler(ISession session)
{
this.session = session;
}
public async Task Update(int id, ProductIdentity productIdentity)
{
var product = session.Get(id);
product.Update(productIdentity);
}
}
Here is the Query Handler for the Get
class GetProductHandler
{
private readonly ISession session;
public GetProductHandler(ISession session)
{
this.session = session;
}
public async Task<Product> Get(int id)
{
var product = session.Get(id);
if (product == null)
throw new Exception("Entity not found");
return Task.FromResult(product);
}
}
Here is the code for the Product entity
class Product
{
public virtual int Id { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string Description { get; protected set; }
public virtual int? Version { get; protected set; }
public virtual void Update(ProductIdentity productIdentity)
{
Name = productIdentity.Name;
Description = productIdentity.Description;
}
}
The flow is
CommittingTransactionCommandHandler is a generic command handler. This is called from the API, which internally invokes the UpdateProductHandler. The transaction is opened in this and committed here.
The scenario is that
I get a Product from the DB using the GetProductHandler. (In this case, the version number of the Product is 10.)
I'm updating the Product using the UpdateProductHandler and commits the session which is under the transaction. (Here version number of the Product is 11)
Immediately after the Update Product, I query the same Product using the GetProductHandler and loads it in the Edit mode in the UI. (But the Product fetched using the GetProductHandler has a version number 10 and not 11.)
Here is the issue, instead of getting the latest update from the DB, the above GetProductHandler, gets the previous state of the object.(Found using the version number)
Now, if I try to update the Product, I get a Stale Object State Exception since the version number is 10 which is not the latest version of the Product.
I've tried with session.Refresh(product) but all in vain as it affects the other transactions.
How can I resolve this?