According to NHProf, the use of implicit transactions is discouraged:
http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions
However, NHibernate LINQ returns an IQueryable<>
when reading objects from the database, and this is lazily evaluated. I have this method in a repository:
public IQueryable<T> GetAll<T>()
{
using (var transaction = _session.BeginTransaction())
{
var data = _session.Linq<T>();
transaction.Commit();
return data;
}
}
The issue here is that the method will commit the transaction before data
is evaluated. Is there a way to use the repository pattern and keep the IQueryable<>
in an explicit transaction? Or is it acceptable for read operations to use implicit transactions?
If you are using repository pattern - no, you should not return IQueryable.
IQueryable is executed. // // Returns: // A System.Type that represents the type of the element(s) that are returned when. // the expression tree associated with this object is executed.
The repository should not create a transaction. That's a responsibility of a separate layer (which depends on the application type).
I'd refactor this to allow external transaction control. The Repository cannot know the scope of the unit of work that various read/write calls are a part of unless the code that makes the calls tells it. Consider setting up a "unit of work" pattern: without revealing specific details of the data store implementation, allow objects that depend on Repository to specify that they are beginning, aborting or completing a "unit of work".
public interface IRepository
{
public UnitOfWork BeginUnitOfWork()
public void CommitUOW(UnitOfWork unit)
public void AbortUOW(UnitOfWork unit)
public IQueryable<T> GetAll<T>(UnitOfWork unit)
public List<T> GetAll<T>()
public void Store<T>(T theObject, UnitOfWork unit)
public void Store<T>(T theObject)
}
Your Repository would probably implement this by maintaining a private Dictionary of SQL transactions, each keyed to a UnitOfWork object (this can be as simple as an empty instantiable class, or it can provide framework-agnostic information about state or metrics). When performing a DB operation, your callers will first ask to begin a UoW, and they will be given a token that they will use to identify the context within which they are making a DB call. The object that gets the token can pass it to other classes that need to perform DB operations in the same operational context. The unit of work will remain open until the dependent class tells the Repository that it is finished, allowing lazy-loads and atomic multi-operation procedures.
Notice that there are overloads that do not require units of work. It is possible, and perhaps necessary, to make simple calls without explicitly starting a unit of work. In these cases, your Repository can create an internal UOW, perform the requested operation, and return the results. However, lazy-loading will be difficult or impossible in these cases; you will have to retrieve the entire result set into a List before ending the internal UoW.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With