Mendz.Data, Dapper, Stored Procedures and Transactions

Using Mendz.Data with Dapper and stored procedures is a great combination. It works well when the primary data source is just one database. Developers can centralize business rules in the database stored procedures. Mendz.Data-based repositories can then be used as the bridge between stored procedures and the domain's POCOs. Simple, right? Well... what happens then when you put transactions in the picture?

In most cases, transactions can be done in the stored procedures themselves. This works well and can be standard practice specially for complex requirements. However, there are situations when transactions need to be started from the C# code. It is recommended to avoid mixing stored procedures transactions with C# side transactions. It is best to have a transaction started from the same object that will end it.

Mendz.Data-based repositories support transactions via built-in BeginTransaction() method. The transaction can be passed as a parameter to Dapper's Execute() method. EndTransaction() can then be used to either commit or rollback.

Using Mendz.Data repository's BeginTransaction() makes sense in clearly identified aggregate roots. However, it can get complicated over time when different domain objects have the potential in the future to be the aggregate root in new requirements. But remember that Dapper is really ADO.Net under the hood, which is TransactionScope-aware. Using TransactionScope helps clear repositories of transaction responsibilities. It also makes the repositories simpler, giving the application or its services the flexibility to manage the transactions themselves regardless of how repository calls are combined/sequenced.

Adding transactions can sometimes require strategic thinking and planning. If you are using stored procedures, consider putting transactions in stored procedures. Be careful though to avoid starting transactions from C# code when calling these stored procedures. To avoid possible mix-up, keep the stored procedures transaction free and let the repositories handle the transactions. To further avoid mix-up with aggregate root concerns, keep the repositories transaction free and let the calling application/service handle the transactions via TransactionScope.

There is really no single approach that can be prescribed. You can apply mixes of these in your application. When problems arise, just be ready to move things around to avoid points where things seem to clash. Be ready. Be flexible. Be smart.

Comments