I have been reading about UnitOfWork pattern for last two days but didn’t understand it correctly.
I have a repository for each class.
eg.
Employee, Attendance, Salary, Department, Address etc.
Repository means- Each of these classes will have their own CRUD operations(creates own database connection). These creates separate database connection and do insert.
Issue arises when I want to do multiple operations as atomic. eg. Insert into Employee and Address in a single transaction. But my repositories do not allow so because Employee is responsible to manage Employee table only.
I can use System.Transactions but this will drive me crazy because of numerous database connections for a single transaction.
Would UoW applies to my case but making some changes?
EDIT:
My sample code
public class AccountTransactionManager
{
Properties.Settings settings = new Properties.Settings();
public void InsertAccountTransaction(AccountTransaction accountTransaction)
{
SqlParameter AccountId = new SqlParameter { ParameterName = "@AccountId", Value = accountTransaction.AccountId, Direction = ParameterDirection.Input, SqlDbType = SqlDbType.Int };
SqlParameter PAYMENT_DATE = new SqlParameter { ParameterName = "@PAYMENT_DATE", Value = accountTransaction.PAYMENT_DATE, Direction = ParameterDirection.Input, SqlDbType = SqlDbType.DateTime };
SqlParameter CURRENT_BALANCE = new SqlParameter { ParameterName = "@CURRENT_BALANCE", Value = accountTransaction.CURRENT_BALANCE, Direction = ParameterDirection.Input, SqlDbType = SqlDbType.Money };
Helper.SqlHelper.Execute(settings.SQLConnectStr
, (tran) =>
{
Helper.SqlHelper.ExecuteNonQuery(tran, CommandType.StoredProcedure, "usp_AccountTransactionInsert", AccountId, PAYMENT_DATE, CURRENT_BALANCE);
});
}
}
SqlHelper code
public static void Execute(string connectionString, Action<SqlTransaction> CallBack)
{
if (CallBack == null)
return;
using (var con = new SqlConnection(connectionString))
{
con.Open();
using (var tran = con.BeginTransaction())
{
#region Call procedures
try
{
CallBack(tran);
tran.Commit();
}
catch (SqlException ex)
{
tran.Rollback();
throw ex;
}
finally
{
con.Close();
}
#endregion
}
}
}
Requirements will be changing very frequently. So should I use any ORM or create my own repository. Would I be able to use stored procedures in ORM?
You have some very wrong assumptions there. First, just because you have two repositories, it doesn’t mean you have two database connections if you use both of them. Database connections are pooled by most ORM’s such as Entity Framework and nHibernate. So you don’t know how connections will be handled, but you can generally be assured that when you call SaveChanges, it will have an implied transaction and occure as a single atomic action.
Second, you’re ignoring one of the key benefits of an ORM, which is navigational properties and collections. If you have an Employee table, then it should have an Address navigational property or Collection of Addresses.
So, say you want to insert a new Employee. You create a new Employee entity, and then create a new Address entity, then add the Address to the Employee, then add the employee to your ORM. When you call Commit or SaveChanges or whatever causes your ORM to update, it updates both entities and it happens as a single transaction.
Likewise, if you add multiple employees, all of them are added as a single transaction when you call SaveChanges.
You would really only need to use System.Transaction if you believe a distributed transaction might be needed. Or, you truly have a multi-step process that cannot be done in a single unit of work.
Much of what you’re talking about is based on assumptions that each Repository is it’s own stand alone unit of work, that is not a necessary assumption at all. UnitOfWorks can be shared between all your repositories. This is even easier to accomplish if you’re using Dependency Injection.
EDIT:
Based on your edit, I see you’re not using an ORM, but rather using a Repository to handle your DAL. Some of what I said still applies, you don’t need each repository to have its own connection, and you don’t need to have a repository only deal with a single entity, as entities have related entities that can be managed as well.
The important thing to remember about UnitOfWork is that it’s a sort of entity cache. You add or update dirty entities to it, and it doesn’t save them one by one… instead, it waits until you call Save, and then it does them all in a single transaction.
Further, a Repository is not a Unit of work, it’s more of a wrapper around a UnitOfWork. Your UnitOfWork keeps track of all entities in the model, not just a single one. So multiple repositories can share a single UnitOfWork.