Sunday, October 15, 2006

.NET TableAdapters Inside TransactionScope

Both TableAdapter and TransactionScope are new in .NET 2.0. Auto-generated TableAdapter and DataTable could play an ORM (Object-relational Mapping) role and act as DAL (Data Access Layer) in an application. TransactionScope wraps the complexity of transaction, and it allows you to put DB interactions inside a transactional block. Using TableAdapter and TransactionScope properly can significantly simplify developers work.

I have just read an article Managing Transactions using TransactionScope that provides an example of using TableAdapter and TransactionScope together:
public static int AddDepartmentWithEmployees(Department dept)
{
int res = 0;

DepartmentAdapter deptAdapter = new DepartmentAdapter();
EmployeeAdapter empAdapter = new EmployeeAdapter();
using (TransactionScope txScope = new TransactionScope())
{
res += deptAdapter.Insert(dept.DepartmentName);
//Custom method made to return Department ID after inserting the department "Identity Column"
dept.DepartmentID = deptAdapter.GetInsertReturnValue();
foreach(Employee emp in dept.Employees)
{

emp.EmployeeDeptID = dept.DepartmentID;
res += empAdapter.Insert(emp.EmployeeName, emp.EmployeeDeptID);
}
txScope.Complete();
}
return res;
}
The code demos using TableAdapter and TransactionScope to insert a Department record and a collection of Employee records in that department into database, presuming SQL Server 2005 in this case to take advantage of lightweight transaction.

Looks really great and simple. But there's an issue of such implementation: Distributed Transaction Coordinator (DTC) is promoted at run time to complete this transaction. A run time error page will show up if DTC is not properly setup in the server; even with DTC configured, overhead of DTC would introduce big performance issues.

The reason is that each TableAdapter maintains its own database connection, and multiple operations with the same TableAdapter would lead to multiple database connections. A lightweight transaction is used in TransactionScope by default with SQL Server 2005, but DTC is promoted if multiple connections exist inside the same TransactionScope, which is the case in the above example.

We all know the cost of DTC is too expensive. Thus it's recommended to avoid using TableAdapters with TransactionScope, or avoid letting TableAdapters to manage the connections. You should manually and explicitly maintain all connections that are involved in a transaction scope if you have to use them together.