Because the ambient transaction
isn't supported with informix
, I pass the transaction and the connection through my methods.
I want to ask about three things:
- Is the following code written well? I mean, no redundant steps and no logical errors.
- Is calling this transaction method with many
null
parameters in a specific case okay? - Is there a better way to handle this problem?
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;
}
Examples for calling:
int res = DocumentFlowModuleDAL.UserTransactionDAL.Insert("InsertRequest", reqObj, typeof(EnhancementRequest), new EnhancementRequest(), transObj, string.Empty, 0,0);
result = UserTransactionDAL.Insert(string.Empty, null, null, null, obj, sp_PostConfirm, x, 0);
1 Answer 1
Do not return error code if possible. If the method fails to do what it needs to do, just throw an exception. In your case, do not return -1, -2, etc, you should create new type of exception and wrap your error code inside.
The using
clause guarantees that Dispose()
of the object you use will be called , even in case of exception, before exiting the enclosed block, so all Close()
and Dispose()
in your code is redundant.
In C#, transaction usage usually goes like
using(var tran = conn.BeginTransaction()) {
try {
...
// your code here
...
tran.Commit();
}
catch {
tran.Rollback();
throw;
}
}
This will work well when you do not return error code.
Edit: Here is an example of the exception class
public enum YourErrorCode {
Unknown,
ErrorCode1,
ErrorCode2,
}
public class YourException : Exception {
public YourErrorCode ErrorCode { get; private set; }
public YourException()
{
}
public YourException(string message)
: base(message)
{
}
public YourException(string message, Exception inner)
: base(message, inner)
{
}
public YourException(YourErrorCode errorCode) : this(errorCode, null)
{
}
public YourException(YourErrorCode errorCode, Exception inner)
: base("The operation failed with error code " + errorCode.ToString(), inner)
{
this.ErrorCode = errorCode;
}
}
And throw it like
throw new YourException(YourErrorCode.ErrorCode1);
instead of returning error code.
-
\$\begingroup\$ thanks ,i know that
The using clause is an automated way to call Dispose() on the object you use
but if my internal method failed to insert before}
does the connection and the transaction dispose or not ? Please explain with code what you mean byyou should create new type of exception and wrap your error code inside.
\$\endgroup\$Anyname Donotcare– Anyname Donotcare2015年03月08日 19:00:20 +00:00Commented Mar 8, 2015 at 19:00 -
1\$\begingroup\$ I added an example of the exception, and fix
using
explanation. And yes theusing
clause guarantees thatDispose()
will be called even in case of exceptions. \$\endgroup\$tia– tia2015年03月08日 23:51:30 +00:00Commented Mar 8, 2015 at 23:51 -
\$\begingroup\$ thanks a lot,i return value because i show the end user error message according to the label , how to show the user error message after throwing exception ? \$\endgroup\$Anyname Donotcare– Anyname Donotcare2015年03月17日 12:28:19 +00:00Commented Mar 17, 2015 at 12:28