Data Access in Orchard 1.7

Topics: Core, Customizing Orchard, Troubleshooting, Writing modules
Sep 9, 2013 at 4:18 AM
I've seen posts in the forums saying that in 1.7 the use of the ambient transaction was being removed, which would mean that the recommendation to suppress the ambient transaction when accessing data outside of the Orchard tables may not be necessary. I watched the podcast of the steering committee meeting from 2/26/2013 and in that podcast this is discussed, and another issue was also discussed, that is the addition of a new RequiresNew method in the transaction manager.

I have also see multiple discussions regarding this error (which I have been seeing in my module):
2013-09-08 19:55:35,904 [6] Orchard.Data.SessionLocator - Error while disposing the transaction.
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'AdoTransaction'.
at NHibernate.Transaction.AdoTransaction.Commit()
at Orchard.Data.SessionLocator.Dispose() in e:\Wayferry\Development\Orchard-Wayferry\src\Orchard\Data\SessionLocator.cs:line 80

I have found that this error occurs because the code SessionLocator.Dispose does not check the transaction before trying to commit or rollback, so the error will occur if the transaction is not active. This should likely be treated as a bug, and changed to check IsActive. In my case the transaction was not active because I was getting the session in a using block (here's an example from Bleroy's OrchardPo module)

using (var session = _sessionLocator.For(typeof(LocalizableStringRecord))) {
...
}

So if you do that, then the session is disposed, which disposes the transaction, so you get the error above later in the request.

So - is there a new set of recommendations for accessing data in Orchard modules that target 1.7 and greater?
Here's what I am doing now, I'm interested to know if anyone has recommendations for improving these - in particular, when do we need to call RequiresNew (3):
  1. Do not suppress the ambient transaction because there isn't one, so it is no longer necessary to do this as it was for modules targeting previous Orchard versions:
    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
    {
    ...
    scope.Complete();
    }
  2. When accessing the NHibernate session, do not access it in a using block, and do not dispose it because the session is managed by Orchard.
  3. Call TransactionManager.RequiresNew() when?
Thanks
Sean
Sep 9, 2013 at 5:04 AM
As far as I understand, use RequireNew() when you want to commit, and start a new transaction. This makes sense for long operations (in my case using a web service to import data in a background task) which can be done in chunks. This should also be good to reduce memory usage of nhibernate session.