如果我创建以下有关事务的方法:
public static int Insert(string processMethod, object[] processParameters, Type processType, object process, UserTransactionDTO transObj, string spPostConfirm, int toEmpNum,int confirmState)
{
int affectedRows = -7;
using (IfxConnection conn = new IfxConnection(ConfigurationManager.ConnectionStrings["crms"].ToString() + " Enlist=true;"))
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
using (IfxTransaction tran = conn.BeginTransaction())
{
if (!string.IsNullOrEmpty(processMethod))//business Method
{
processParameters[1] = conn;
processParameters[2] = tran;
MethodInfo theMethod = processType.GetMethod(processMethod, new[] { processParameters.First().GetType(), typeof(IfxConnection), typeof(IfxTransaction) });
object res = theMethod.Invoke(process, processParameters);
transObj.ValuesKey = res.ToString();
}
if (!string.IsNullOrEmpty(transObj.ValuesKey))
{
affectedRows = RunPreConfirm(transObj.TaskCode, transObj.UserStateCode, transObj.ValuesKey, conn, tran, confirmState);//sp_confirm
if (affectedRows != 1)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
affectedRows = InsertTrans(transObj, conn, tran);//MainTransaction --->df2usertrans
if (affectedRows == 1)//Success
{
if (!string.IsNullOrEmpty(spPostConfirm))
{
affectedRows = RunPostConfirm(spPostConfirm, transObj.ValuesKey, conn, tran);//sp_post_confirm
if (affectedRows != 0)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -2;//Fail
}
}
affectedRows = RunAfterTrans(transObj.TaskCode, transObj.OldStatusCode, transObj, toEmpNum, conn, tran);//sp_after_trans
if (affectedRows != 1)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -3;//Fail
}
tran.Commit();
tran.Dispose();
conn.Close();
conn.Dispose();
return 1;
}
else
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
}
else
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
}
}
return affectedRows;
}
我想问三个问题:
1-如果我的内部方法之一未能在}
之前插入连接和事务是否自动处置和关闭?我的意思是我应该调用以下代码块:
tran.Dispose();
conn.Close();
conn.Dispose();
2-我可以调用带有其属性的实例方法而不是填充对象并再次将其作为参数传递吗?
object res = theMethod.Invoke(process, processParameters);
我的意思是:我想使用它(及其对象状态),因为它是实例方法:
public string InsertRequest(IfxConnection conn,IfxTransaction trans)
而不是当前的方法:
public string InsertRequest(EnhancementRequest obj, IfxConnection conn,IfxTransaction trans)
3-下面的代码写得好吗?我的意思是,没有多余的步骤,也没有逻辑错误。?
代码有一些冗余和一些可能的问题。
首先,如果您使用 using 语句缩小连接和事务对象的范围,则无需对这些对象中的任何一个调用 Dispose,因为 using 将为您处理它。
如果调用存储过程的函数不处理数据库异常,则应添加 try .. 除了扩展事务范围:
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
// All db operations here
tran.Commit();
}
catch(Exception e)
{
tran.Rollback();
throw; // Or return error code
}
}
因此,如果某些非异常验证条件失败,则只需调用 trans。回滚() 并返回您的错误代码。
关于您的问题 2,我建议添加通用调用作为您的函数参数:
public static int Insert(Func<IfxConnection, IfxTransaction, object> callback)
{
// ...
object res = callback(conn, tran);
// ...
}
在上面的代码中,我使用了通用委托 Func,您可以像这样调用插入函数:
Insert((conn, tran) =>
{
// do something here with conn and tran and return object
});
或者,您可以声明自己的委托签名,如果您计划将来更改它,这会很有帮助:
public delegate object MyDelegateType(IfxConnection conn, IfxTransaction tran);
然后,在调用 insert 时,只需将您选择的对象和方法作为参数传递:
public class SomeClass
{
public static object ProcessOnInsert(IfxConnection conn, IfxTransaction tran)
{
// do something here with conn and tran
}
public static int Insert(MyDelegateType callback)
// or
// public static int Insert(Func<IfxConnection,IfxTransaction,object> callback)
{
// ...
callback(conn, tran);
// ...
}
public static void RunInsert()
{
Insert(ProcessOnInsert);
}
}
经过一些更改后的方法:
public static int Insert(Func<IfxConnection, IfxTransaction, object> processMethod, UserTransactionDTO transObj, string spPostConfirm, int toEmpNum, int confirmState)
{
int affectedRows = -7;
using (IfxConnection conn = new IfxConnection(ConfigurationManager.ConnectionStrings["crms"].ToString() + " Enlist=true;"))
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
if (processMethod != null)//business Method
{
object res = processMethod(conn, tran);
transObj.ValuesKey = res.ToString();
}
if (string.IsNullOrEmpty(transObj.ValuesKey)) //Fail
{
tran.Rollback();
return -1;//Fail
}
affectedRows = RunPreConfirm(transObj.TaskCode, transObj.UserStateCode, transObj.ValuesKey, conn, tran, confirmState);//sp_confirm
if (affectedRows != 1)
{
tran.Rollback();
return -1;//Fail
}
affectedRows = InsertTrans(transObj, conn, tran);//MainTransaction --->df2usertrans
if (affectedRows != 1)//Fail
{
tran.Rollback();
return -1;//Fail
}
if (!string.IsNullOrEmpty(spPostConfirm))
{
affectedRows = RunPostConfirm(spPostConfirm, transObj.ValuesKey, conn, tran);//sp_post_confirm
if (affectedRows != 0)
{
tran.Rollback();
return -2;//Fail
}
}
affectedRows = RunAfterTrans(transObj.TaskCode, transObj.OldStatusCode, transObj, toEmpNum, conn, tran);//sp_after_trans
if (affectedRows != 1)
{
tran.Rollback();
return -3;//Fail
}
tran.Commit();
return 1;
}
catch
{
trans.Rollback();
throw;
}
}
}
return affectedRows;
}
调用此函数时,只需将具有匹配签名的任何实例方法作为 processMethod 传递即可。
另一个建议是更改所有函数以使用类似的回调语法,而不是传递字符串和对象参数,而是直接调用该方法,因为在这种情况下,强类型提供了更多的可读性。
关于在事务中运行一系列操作时的可读性,如果其中一个失败,整个事务需要失败,最好减少嵌套条件并首先检查失败(见上文)。