If I understood you right, you want a way to avoid unneeded transactions from being created?
For this, I suggest you create one BaseUnitOfWork type and two other types: ReadOnlyUnitOfWork and ReadWriteUnitOfWork.
Then, you would use only the ReadOnly, when selecting stuff and ReadWrite when you need to do both.
The skeleton in C# would be something like.
public class BaseUnitOfWork // YOUR INTERFACES HERE
{
/// <summary>
/// DB context.
/// </summary>
private IDBManager _dbManager;
/// <summary>
/// Repository provider class which can create repositories on demand.
/// </summary>
private IRepositoryProvider _repositoryProvider;
public BaseUnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider)
{
_dbManager = dbManager;
_repositoryProvider = repoProvider;
}
public T GetRepository<T>()
{
return _repositoryProvider.Create<T>(_dbManager);
}
}
public class ReadOnlyUnitOfWork : BaseUnitOfWork
{
public ReadOnlyUnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider) : base(dbManager,repoProvider)
{
_dbManager = dbManager;
_repositoryProvider = repoProvider;
}
}
public class ReadWriteUnitOfWork : BaseUnitOfWork// YOUR INTERFACES HERE
{
private TransactionScope _transaction;
public ReadWriteUnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider) : base(dbManager,repoProvider)
{
if (_transaction == null)
_transaction = new TransactionScope();
}
public void Save()
{
_transaction.Complete();
}
public void Dispose()
{
_transaction.Dispose();
}
}
I use this strategy already successfully in several projects.
The good part of this strategy, is that you comply with the S in SOLID (http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) design: Single responsibility.
One class has the responsibility to handle databases operations with transactions, while the other just handle transactionless operations.
Also, you must understand that the unit of work block should be quick (in execution) and (if possible) small in code (as a best practices).
Therefore, you could use it something like this:
using( IReadWriteUnitOfWork uow = InjectionFramework.ResolveDependencyOfType<IReadWriteUnitOfWork>() )
{
//do your database stuff here, try to keep it simple.
//after doing everything, you **commit** the transaction (in your case, you save)
uow.Save();
}
The good part of using command is that after you have completed this piece of code it will automatically call your dispose method.