View Single Post
  #1 (permalink)  
Old November 20th, 2018, 08:00 AM
ChrisDev ChrisDev is offline
Registered User
Points: 8, Level: 1
Points: 8, Level: 1 Points: 8, Level: 1 Points: 8, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Nov 2018
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default Unit of Work and TransactionScope

I've been implementing some of the patterns from Chapter 7, including the Unit of Work + repository for Dapper (and SQL db persistence), and I encountered an issue around performance.

The use of TransactionScope in the UoW, while very simple and elegant, seems to cause a huge performance overhead. In an integration test project where I add an aggregate with 1000 child objects, using TransactionScope makes the test execution time increase about ten-fold. In order to overcome this, I added some additional code to the UnitOfWork and Repository classes to allow the UnitOfWork to open the connection and begin the transaction on the first of the repositories registered with it - this transaction is then passed into each of the peristence methods so that they can make use of it.

This makes the UoWRepo interface looks like so:

Code:
    public interface IUnitOfWorkRepository
    {
        Task<IDbTransaction> BeginTransaction();
        Task PersistCreationOf(IAggregate aggregate, IDbTransaction tran);
        Task PersistUpdateOf(IAggregate aggregate, IDbTransaction tran);
    }
And in the repo implementation:

Code:
    public async Task<IDbTransaction> BeginTransaction()
    {
        var connection = GetConnection();
        await connection.OpenAsync();
        return connection.BeginTransaction();
    }
And finally, in the UoW Commit method:

Code:
	
	//Having kept tabs on the first repo registered, now begin tran
    var tran = await _initialRepository.BeginTransaction();
    var connection = tran.Connection;

    using (connection)
    {
        using (tran)
        {
            foreach (var entity in _addedEntities.Keys)
            {
                await _addedEntities[entity].PersistCreationOf(entity, tran);
            }

            foreach (var entity in _changedEntities.Keys)
            {
                await _changedEntities[entity].PersistUpdateOf(entity, tran);
            }

            tran.Commit();
        }
        connection.Close();
    }
The persistence methods then simply make use of the tran, and execute against the connection associated with the tran. This works, and I see vastly improved performance.

However, I wanted to know whether anyone else had encountered any performance issues with TransactionScope (I had anticipated *some* overhead, but not this much), and whether I am guilty of any error in the above approach. I am not concerned about distributed/escalated transactions, etc. so don't actually need a lot of the added value of TransactionScope.

Thoughts appreciated!
Reply With Quote