SubSonic中使用TransactionScope
SubSonic使用起来非常像Rails中的ActiveRecord,不仅将代码生成工具集成到了IDE中,而且还可以自己来定制模板。虽然还存在问题,但现在的版本是可以满足日常开发了。
由于把数据库操作封装起来了,因此现有的事务处理方式并不能满足需求,在这之前一直在使用Castle ActiveRecord进行开发,它提供的TransactionScope使用非常方便,这次改造也得益于Castle ActiveRecord。
一、DataProvider改造
添加如下代码:
//jy
protected bool _IsNeedTransaction = false;
protected DbTransaction _Transaction;
internal void BeginShareTransaction()
{
if (__sharedConnection == null ||
__sharedConnection.State != ConnectionState.Open)
{
InitializeSharedConnection();
}
_Transaction = __sharedConnection.BeginTransaction();
_IsNeedTransaction = true;
}
internal void BeginShareTransaction(IsolationLevel level)
{
if (__sharedConnection == null ||
__sharedConnection.State != ConnectionState.Open)
{
InitializeSharedConnection();
}
_Transaction = __sharedConnection.BeginTransaction(level);
_IsNeedTransaction = true;
}
internal void PrcessTransaction(bool rollback)
{
try
{
if (_Transaction != null)
{
if (!rollback)
{
_Transaction.Commit();
}
else
{
_Transaction.Rollback();
}
}
else
{
throw new ApplicationException("请先实例化TrancactionScope类启动事务!");
}
}
finally
{
if (__sharedConnection.State == ConnectionState.Open)
{
__sharedConnection.Close();
}
__sharedConnection.Dispose();
}
}
//jy end
protected bool _IsNeedTransaction = false;
protected DbTransaction _Transaction;
internal void BeginShareTransaction()
{
if (__sharedConnection == null ||
__sharedConnection.State != ConnectionState.Open)
{
InitializeSharedConnection();
}
_Transaction = __sharedConnection.BeginTransaction();
_IsNeedTransaction = true;
}
internal void BeginShareTransaction(IsolationLevel level)
{
if (__sharedConnection == null ||
__sharedConnection.State != ConnectionState.Open)
{
InitializeSharedConnection();
}
_Transaction = __sharedConnection.BeginTransaction(level);
_IsNeedTransaction = true;
}
internal void PrcessTransaction(bool rollback)
{
try
{
if (_Transaction != null)
{
if (!rollback)
{
_Transaction.Commit();
}
else
{
_Transaction.Rollback();
}
}
else
{
throw new ApplicationException("请先实例化TrancactionScope类启动事务!");
}
}
finally
{
if (__sharedConnection.State == ConnectionState.Open)
{
__sharedConnection.Close();
}
__sharedConnection.Dispose();
}
}
//jy end
二、添加TransactionScope类
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Data;
namespace SubSonic
{
/// <summary>
/// 使用共享连接完成事务处理。
/// </summary>
public class TransactionScope : IDisposable
{
DataProvider _Provider = null;
bool _IsRollback = false;
#region 构造函数
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
public TransactionScope()
{
_Provider = DataService.GetInstance(null);
_Provider.BeginShareTransaction();
}
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
/// <param name="level">事务级别</param>
public TransactionScope(IsolationLevel level)
{
_Provider = DataService.GetInstance(null);
_Provider.BeginShareTransaction(level);
}
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
/// <param name="ProviderName">提供器名称</param>
public TransactionScope(string ProviderName)
{
_Provider = DataService.GetInstance(ProviderName);
_Provider.BeginShareTransaction();
}
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
/// <param name="ProviderName">提供器名称</param>
/// <param name="level">事务级别</param>
public TransactionScope(string ProviderName,IsolationLevel level)
{
_Provider = DataService.GetInstance(ProviderName);
_Provider.BeginShareTransaction(level);
}
#endregion
/// <summary>
/// 标记为提交状态。
/// </summary>
public void VoteCommit()
{
if (_IsRollback)
{
throw new ApplicationException("当前事务已回滚,不能再进行提交操作!");
}
}
/// <summary>
/// 标记为回滚状态。
/// </summary>
public void VoteRollback()
{
_IsRollback = true;
}
#region IDisposable 成员
/// <summary>
///
/// </summary>
public void Dispose()
{
_Provider.PrcessTransaction(_IsRollback);
}
#endregion
}
}
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Data;
namespace SubSonic
{
/// <summary>
/// 使用共享连接完成事务处理。
/// </summary>
public class TransactionScope : IDisposable
{
DataProvider _Provider = null;
bool _IsRollback = false;
#region 构造函数
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
public TransactionScope()
{
_Provider = DataService.GetInstance(null);
_Provider.BeginShareTransaction();
}
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
/// <param name="level">事务级别</param>
public TransactionScope(IsolationLevel level)
{
_Provider = DataService.GetInstance(null);
_Provider.BeginShareTransaction(level);
}
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
/// <param name="ProviderName">提供器名称</param>
public TransactionScope(string ProviderName)
{
_Provider = DataService.GetInstance(ProviderName);
_Provider.BeginShareTransaction();
}
/// <summary>
/// 构造函数,开始事务处理。
/// </summary>
/// <param name="ProviderName">提供器名称</param>
/// <param name="level">事务级别</param>
public TransactionScope(string ProviderName,IsolationLevel level)
{
_Provider = DataService.GetInstance(ProviderName);
_Provider.BeginShareTransaction(level);
}
#endregion
/// <summary>
/// 标记为提交状态。
/// </summary>
public void VoteCommit()
{
if (_IsRollback)
{
throw new ApplicationException("当前事务已回滚,不能再进行提交操作!");
}
}
/// <summary>
/// 标记为回滚状态。
/// </summary>
public void VoteRollback()
{
_IsRollback = true;
}
#region IDisposable 成员
/// <summary>
///
/// </summary>
public void Dispose()
{
_Provider.PrcessTransaction(_IsRollback);
}
#endregion
}
}
三、SqlDataProvider改造
在每一个新建了SqlCommand的地方都添加以下代码: //jy
if (_IsNeedTransaction)
{
cmd.Transaction = _Transaction as SqlTransaction;
}
//jy end
if (_IsNeedTransaction)
{
cmd.Transaction = _Transaction as SqlTransaction;
}
//jy end
其它数据库提供器的也使用相同的方法进行改造。
四、使用示例
/// <summary>
/// 收货处理。
/// </summary>
/// <param name="id"></param>
/// <param name="UserId"></param>
public static void Receiving(object id,object UserId)
{
using (TransactionScope tran = new TransactionScope())
{
try
{
LogiPackage lp = new LogiPackage(id);
string strSql = "";
LogiWarehouse lw = new LogiWarehouse();
LogiPackageDetailCollection lpds = lp.LogiPackageDetails();
//foreach (LogiPackageDetail d in lpds)
//{
// Query q = LogiWarehouse.Query();
// q.AddWhere("Freight_Id", d.FreightId);
// //检查发送人的库存
// q.AND("Company_Id", lp.SendId);
// lw.LoadAndCloseReader(q.ExecuteReader());
// //if (lw.Count < d.Count)
// //{
// // throw new ProcessErrorException("库存不足,请检查!");
// //}
//}
foreach (LogiPackageDetail d in lpds)
{
Add(lp.InceptId, d.FreightId, d.Count);
Dec(lp.SendId, d.FreightId, d.Count);
}
LogiPackageStatus lps = new LogiPackageStatus("Code", 3);
lp.StatuId = lps.Id;
lp.Save();
Log(new Guid(UserId.ToString()), lps.Id, lp.Id);
tran.VoteCommit();
}
catch
{
tran.VoteRollback();
throw;
}
}
/// 收货处理。
/// </summary>
/// <param name="id"></param>
/// <param name="UserId"></param>
public static void Receiving(object id,object UserId)
{
using (TransactionScope tran = new TransactionScope())
{
try
{
LogiPackage lp = new LogiPackage(id);
string strSql = "";
LogiWarehouse lw = new LogiWarehouse();
LogiPackageDetailCollection lpds = lp.LogiPackageDetails();
//foreach (LogiPackageDetail d in lpds)
//{
// Query q = LogiWarehouse.Query();
// q.AddWhere("Freight_Id", d.FreightId);
// //检查发送人的库存
// q.AND("Company_Id", lp.SendId);
// lw.LoadAndCloseReader(q.ExecuteReader());
// //if (lw.Count < d.Count)
// //{
// // throw new ProcessErrorException("库存不足,请检查!");
// //}
//}
foreach (LogiPackageDetail d in lpds)
{
Add(lp.InceptId, d.FreightId, d.Count);
Dec(lp.SendId, d.FreightId, d.Count);
}
LogiPackageStatus lps = new LogiPackageStatus("Code", 3);
lp.StatuId = lps.Id;
lp.Save();
Log(new Guid(UserId.ToString()), lps.Id, lp.Id);
tran.VoteCommit();
}
catch
{
tran.VoteRollback();
throw;
}
}
目前已成功在http://www.massany.com和帮朋友做的一个物流系统中使用。
有更好的改进建议,希望大家交流一下!SubSonic修改过的工程下载:https://files.cnblogs.com/jinyong/subsonic2.1.zip