如果我创建以下有关交易的方法:
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 - 以下代码写得好吗?我的意思是,没有冗余的步骤,没有逻辑错误。?
答案 0 :(得分:4)
代码有一些冗余和一些可能的问题。
首先,如果使用using语句缩小连接和事务对象的范围,则无需在任何这些对象上调用Dispose,因为使用它将为您处理。
如果调用存储过程的函数没有处理数据库异常,你应该添加try ..除了处理你的事务范围:
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
// All db operations here
tran.Commit();
}
catch(Exception e)
{
tran.Rollback();
throw; // Or return error code
}
}
如果有一些非异常验证条件失败,你只需要调用trans.Rollback()并返回错误代码即可。
关于你的问题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。
另一个建议是更改所有函数以使用类似的回调语法,而不是传递字符串和对象参数,直接调用方法,因为强类型在这种情况下提供更多的可读性。
关于在事务中运行一系列操作时的可读性,如果其中一个操作失败,整个事务需要失败,最好减少嵌套条件并首先检查失败(见上文)。