2
\$\begingroup\$

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:

  1. Is the following code written well? I mean, no redundant steps and no logical errors.
  2. Is calling this transaction method with many null parameters in a specific case okay?
  3. 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);
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Mar 8, 2015 at 10:39
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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.

answered Mar 8, 2015 at 15:19
\$\endgroup\$
3
  • \$\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 by you should create new type of exception and wrap your error code inside. \$\endgroup\$ Commented Mar 8, 2015 at 19:00
  • 1
    \$\begingroup\$ I added an example of the exception, and fix using explanation. And yes the using clause guarantees that Dispose() will be called even in case of exceptions. \$\endgroup\$ Commented 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\$ Commented Mar 17, 2015 at 12:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.