If i create the following method concerning transaction :
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;
}
I want to ask three questions :
1-if one of my internal methods failed to insert before } Does the connection and the transaction disposed and closed automatically or not ?I mean should i call the following block of code :
tran.Dispose();
conn.Close();
conn.Dispose();
2-Could i invoke an instance method with its properties instead of fill the object and passing it as a parameter again ?
object res = theMethod.Invoke(process, processParameters);
I mean :
I want to use this(with its object state) because it's instance method:
public string InsertRequest(IfxConnection conn,IfxTransaction trans)
instead of this current method :
public string InsertRequest(EnhancementRequest obj, IfxConnection conn,IfxTransaction trans)
3-Is the following code written well? I mean, no redundant steps and no logical errors.?
The code has some redundancies and some possible issues.
First of all if you are narrowing scope of connection and transaction objects with using statement, you don't need to call Dispose on any of these objects as using will take care of it for you.
If your functions calling stored procedures are not handling database exceptions you should add try .. except aroung your transaction scope:
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
// All db operations here
tran.Commit();
}
catch(Exception e)
{
tran.Rollback();
throw; // Or return error code
}
}
So effectively if some non-exception validation condition fails you just need to call trans.Rollback() and return your error code.
Regarding your question 2 I would suggest adding generic call as your function parameter:
public static int Insert(Func<IfxConnection, IfxTransaction, object> callback)
{
// ...
object res = callback(conn, tran);
// ...
}
In the code above I used generic delegate Func, you can call your insert function like this:
Insert((conn, tran) =>
{
// do something here with conn and tran and return object
});
Alternatively you can declare your own delegate signature which can be helpful if you plan to change it in the future:
public delegate object MyDelegateType(IfxConnection conn, IfxTransaction tran);
Then when calling insert just pass the object and method of your choice as an argument:
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);
}
}
The method after some changes:
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;
}
When calling this function just pass any instance method with matching signature as processMethod.
Another suggestion is to change all functions to use the similar callback syntax and instead of passing string and object arguments, call the method directly as strong typing in this case gives more readability.
Regarding readability as you run of series of operations in a transaction and if either one fails, whole transaction needs to fail, it's better to reduce nested conditions and check for fail first (see above).
Related
I have two methods that connect to the database and I try to avoid double code
one of my methods is one that can run alon (open itself SqlConnection and close it)
another method using existing SqlConnection and using SqlTransaction also (I don't want to open another connection and also I don't want to close it)
my first method :
public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject)
{
List<CSerieses> CSerieses = new List<CSerieses>();
try
{
using (SqlConnection openCon = new SqlConnection(connectionString))
{
string query = "SELECT [CSeriesNum],[CCount],[Mark] from [Serieses] " +
"where [TestPrimary]=#deliveryNumber";
SqlCommand command = new SqlCommand(query, openCon);
command.Parameters.AddWithValue("#deliveryNumber", DeliveryReportObject.DeliveryNumber);
openCon.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
CSerieses.Add(new CSerieses(reader.GetString(0), reader.GetInt32(1), reader.GetBoolean(2)));
}
}
openCon.Close();
}
}
catch (Exception ex)
{
LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
}
return CSerieses;
}
The method that using on the transaction :
public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject,
SqlConnection co,SqlTransaction tran)
{
List<CSerieses> CSerieses = new List<CSerieses>();
try
{
using (co)
{
string query = "SELECT [CSeriesNum],[CCount],[Mark] from [Serieses] " +
"where [TestPrimary]=#deliveryNumber";
SqlCommand command = new SqlCommand(query, co, tran);
command.Parameters.AddWithValue("#deliveryNumber", DeliveryReportObject.DeliveryNumber);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
CSerieses.Add(new CSerieses(reader.GetString(0), reader.GetInt32(1), reader.GetBoolean(2)));
}
}
}
}
catch (Exception ex)
{
LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
}
return CSerieses;
}
I try to combine them :
public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject,
SqlConnection co = null,SqlTransaction tran = null)
{
List<CSerieses> CSerieses = new List<CSerieses>();
try
{
using (co ?? new SqlConnection(connectionString))
{
if (co.IsOpened() == false)
{
co.Open();
}
string query = "SELECT [CSeriesNum],[CCount],[Mark] from [Serieses] " +
"where [TestPrimary]=#deliveryNumber";
SqlCommand command = new SqlCommand(query, co, tran);
if(tran != null)
{
command.Transaction = tran;
}
command.Parameters.AddWithValue("#deliveryNumber", DeliveryReportObject.DeliveryNumber);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
CSerieses.Add(new CSerieses(reader.GetString(0), reader.GetInt32(1), reader.GetBoolean(2)));
}
}
}
}
catch (Exception ex)
{
LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
}
return CSerieses;
}
It does not work for me. I have no idea how to check if it null in using and if yes to create a new instance of SqlConnection that should close at the end of the using statement
And I do it the right way anyway?
This is a major problem:
using (co ?? new SqlConnection(connectionString))
If co is passed in, then you don't own it - the caller does - so: you shouldn't be disposing it. What I would suggest here is:
bool ownConnection = false;
try
{
if (co is null)
{
ownConnection = true;
co = new SqlConnection(...);
co.Open();
}
// your code here
}
finally
{
if (ownConnection)
{
co?.Dispose();
}
}
or wrap that up in a helper - perhaps a custom disposable that takes a connection and connection string:
public readonly struct ConnectionWrapper : IDisposable
{
private readonly bool owned;
public SqlConnection Connection { get; }
public ConnectionWrapper(SqlConnection connection, string connectionString)
{
if (connection is null)
{
owned = true;
Connection = new SqlConnection(connectionString);
Connection.Open();
}
else
{
owned = false;
Connection = connection;
}
}
public void Dispose()
{
if (owned)
{
Connection?.Dispose();
}
}
}
then you can just use:
using var wrapped = new ConnectionWrapper(co, connectionString);
// your code, using wrapped.Connection
This seems that kind of situation that perfectly fits the overload concept.
The GetCSerieses method should have two versions, the first one builds its own connection and transaction, the second one takes both a non optional connection and a non optional transaction. The first one, after creating the connection and the transaction calls the second one.
Now if a third method requires a call the GetCSerieses could pass its own connection and transaction, while a call without them will be handled by the first overload
public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject)
{
using(SqlConnection con = new SqlConnection(......))
{
try
{
con.Open();
using(SqlTransaction tran = con.BeginTransaction())
{
return GetCSerieses(DeliveryReportObject, con, tran);
}
// Or, if you don't need a transaction you could call the
// overload passing null
// return GetCSerieses(DeliveryReportObject, con, null);
}
catch(Exception ex)
{
LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
return null; // ?? or return new List<CSerieses>();
}
}
}
public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject, SqlConnection co, SqlTransaction tran)
{
List<CSerieses> CSerieses = new List<CSerieses>();
try
{
// We don't own the connection and the transaction object.
// Whoever passed them to us is responsible of their disposal.
string query = "......";
SqlCommand command = new SqlCommand(query, co, tran);
command.Transaction = tran;
....
}
catch (Exception ex)
{
LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
}
return CSerieses;
}
I'm using .Net Compact 3.5 Windows 7 CE.
I have an application with about 50 users, I have it setup so that I would get an email every time a database transaction failed, with the query.
Every so often I would get an email with a stack trace that starts like this:
System.ArgumentException: Value does not fall within the expected range.
at System.Data.SqlClient.SqlParameterCollection.Validate(Int32 index, SqlParameter value)
at System.Data.SqlClient.SqlParameterCollection.AddWithoutEvents(SqlParameter value)
at System.Data.SqlClient.SqlParameterCollection.Add(SqlParameter value)
at MedWMS.Database.startSqlConnection(String query, SqlParameter[] parameters, SqlConnection connection, SqlCommand cmd)
at MedWMS.Database.<>c__DisplayClasse.b__8()
at MedWMS.Database.retry(Action action)
at MedWMS.Database.executeNonQuery(String query, SqlParameter[] parameters, String connectionString)...
The SQL query which causes this issue is not always the same. I run the same query seconds after I get the email in SQL Server Management Studio with no issues.
I would like to know why this could be happening. This is my first question on SO so please let me know if I'm doing something wrong. I would be happy to answer any questions to provide more detail.
This is a sample of the code that would cause this error:
SqlParameter[] parameters = new SqlParameter[1];
parameters[0] = new SqlParameter("#salesOrder", this.salesOrderNumber);
string query = #"
Select InvTermsOverride from SorMaster where SalesOrder = Convert(int, #salesOrder) and InvTermsOverride = '07' --07 is for COD";
DataTable dt = Database.executeSelectQuery(query, parameters, Country.getCurrent().getSysproConnectionStrReportServer());
This is the query that actually gets passed:
Select InvTermsOverride from SorMaster where SalesOrder = Convert(int, '000000001138325') and InvTermsOverride = '07' --07 is for COD
Here is the relevant methods from the Database class:
public static DataTable executeSelectQuery(String query, SqlParameter[] parameters, string connectionString)
{
DataTable dt = new DataTable();
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = null;
try
{
retry(() =>
{
cmd = startSqlConnection(query, parameters, connection, cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
dt.Load(reader);
}
});
}
catch (Exception ex)
{
onDbConnectionCatch(cmd, ex);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
return dt;
}
public static void executeNonQuery(String query, SqlParameter[] parameters, string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = null;
try
{
retry(() =>
{
cmd = startSqlConnection(query, parameters, connection, cmd);
cmd.ExecuteNonQuery();
});
}
catch (Exception ex)
{
onDbConnectionCatch(cmd, ex);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
}
private static void retry(Action action)
{
int retryCount = 3;
int retryInterval = 1000;
Exception lastException = null;
for (int retry = 0; retry < retryCount; retry++)
{
try
{
if (retry > 0)
System.Threading.Thread.Sleep(retryInterval);
action();
lastException = null;
return;
}
catch (Exception ex)
{
lastException = ex;
}
}
if (lastException != null)
{
throw lastException;
}
}
private static SqlCommand startSqlConnection(String query, SqlParameter[] parameters, SqlConnection connection, SqlCommand cmd)
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
cmd = new SqlCommand(query, connection);
if (parameters != null)
{
foreach (SqlParameter sp in parameters)
{
if (sp != null)
{
cmd.Parameters.Add(sp);
}
}
}
return cmd;
}
private static void onDbConnectionCatch(SqlCommand cmd, Exception ex)
{
try
{
new BigButtonMessageBox("", "Unable connect to database").ShowDialog();
sendEmailWithSqlQuery(cmd, ex);
}
catch
{
}
}
private static void sendEmailWithSqlQuery(SqlCommand cmd, Exception ex)
{
string query2 = "cmd was null";
if (cmd != null)
{
query2 = cmd.CommandText;
foreach (SqlParameter p in cmd.Parameters)
{
query2 = query2.Replace(p.ParameterName, "'" + p.Value.ToString() + "'");
}
}
InternetTools.sendEmail("DB ERROR", ex.ToString() + "\r\n" + query2);
}
I had the same issue as Can't solve "Sqlparameter is already contained by another SqlparameterCollection"
For some reason SQL CE has a different error.
Because of my retry method, I couldn't reuse the SqlParameter object, still not sure why it's not allowed
Anyways I changed
cmd.Parameters.Add(sp);
to
cmd.Parameters.Add(sp.ParameterName, sp.Value);
I have a stored procedure that returns a single record, either null or data if present.
In my code I need to check what that procedure returns. What is the right way to do it?
Now when, running the code I have an exception saying: "Invalid attempt to read when no data is present." I'm using Visual Studio 2005.
Here is my method:
public static String GetRegionBasedOnIso(String isoNum)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString);
String region = null;
try
{
using (SqlCommand cmd = new SqlCommand("MyProc", conn))
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#isoNum", isoNum);
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.IsDBNull(0))
{
return null;
}
else
{
region = (String)dr["region"];
}
}
}
}
catch (Exception e)
{
throw new System.Exception(e.Message.ToString());
}
finally
{
conn.Close();
}
return region;
}
What can I do to fix it? Thank you
if (dr.Read())
{
if (dr.IsDBNull(0))
{
return null;
}
else
{
region = (String)dr["region"];
}
}
else
{
// do something else as the result set is empty
}
This is a .cs page and I have two function to be executed, But the error is both the function are not being executed ,if I comment on one function the other will work, both are not executed,it giving a common error object reference not set to an instance of an object
Below specified is a .cs page.
Business bus = new Business();
try
{
intResult = bus.create_user(ua);
}
catch (Exception ex)
{
}
finally
{
bus = null;
}
int intres = 0;
try
{
intres = bus.fninsertuser_role_map(ua, role, i);
}
catch (Exception ee)
{
}
finally
{
bus = null;
}
Data access object
public int create_user(UserMaster ua)
{
// Connection connect = new Connection();
try
{
return cs.create_user(ua);
}
catch (Exception e)
{
throw e;
}
finally
{
cs = null;
}
}
public int fninsertuser_role_map(UserMaster ua, int[] role, int i)
{
// Connection connect = new Connection();
try
{
return cs.fninsertuser_role_map(ua, role, i);
}
catch (Exception e)
{
throw e;//**Throws the exception here.**
}
finally
{
//cs = null;
}
Business value object
public int create_user(UserMaster ua)
{
SqlConnection Con = new SqlConnection(str);
Con.Open();
SqlCommand Cmd = new SqlCommand("createuser", Con);
Cmd.CommandType = CommandType.StoredProcedure;
try
{
log.Debug("Inside Create user");
Cmd.Parameters.AddWithValue("#User_Id", ua.UserName);
Cmd.Parameters.AddWithValue("#Password", ua.Password);
Cmd.Parameters.AddWithValue("#Name", ua.Name);
Cmd.Parameters.AddWithValue("#Role_Id", ua.Role);
Cmd.Parameters.AddWithValue("#Department_Id", ua.Department);
Cmd.Parameters.AddWithValue("#Active", ua.Active);
log.Debug("Inside Create_User: New User created having ID: " + ua.UserName);
log.Info("user created");
return Cmd.ExecuteNonQuery();
}
catch (Exception e)
{
log.Debug("Error: Inside catch block of Create User");
log.Error("Error msg:" + e);
log.Error("Stack trace:" + e.StackTrace);
throw e;
}
finally
{
Cmd.Dispose();
Con.Close();
Con.Dispose();
}
}
/*Function to insert into user_role_map*/
public int fninsertuser_role_map(UserMaster u, int[] role, int i)
{
SqlConnection Con = new SqlConnection(str);
Con.Open();
transaction = Con.BeginTransaction();
int result = 0;
for (int a = 0; a < i; a++)
{
SqlCommand Cmd = new SqlCommand("create_UR_Map", Con, transaction);
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.Parameters.Clear();
Cmd.Parameters.AddWithValue("#User_Id", u.UserName);
Cmd.Parameters.AddWithValue("#Role_Id", role[a]);
result = Cmd.ExecuteNonQuery();
}
transaction.Commit();
return result;
}
I just need to execute both the function in the same page.Any help are appreciated.
Problem : you are trying to put null into instance variable bus and then calling methods using the same variable as below:
try
{
intResult = bus.create_user(ua);
}
catch (Exception ex)
{
}
finally
{
bus = null;//bus becomes null here for sure even if there is no excption thrown
}
int intres = 0;
try
{
intres = bus.fninsertuser_role_map(ua, role, i);//throws exception here
}
that is why it throws object reference not set to an instance of an object.
Note : You should remember that finally block willbe executed irrespective of the situation means it will be executed in all the cases and your instance variable bus becomes null for sure even if there is no exception thrown.
Solution : i think you need to really refactor your code but your intension is to making instance variable bus to null if it throws exception if that is the case move that statement inside the catch block.
Try This:
try
{
intResult = bus.create_user(ua);
}
catch (Exception ex)
{
bus = null;
}
finally
{
//any code which needs to be executed for sure
}
int intres = 0;
try
{
intres = bus.fninsertuser_role_map(ua, role, i);
}
catch (Exception ee)
{
bus = null;
}
finally
{
//any code which needs to be executed for sure
}
We have this class to use like SingleTon to return the same connection and transaction(isolation level read commited)(we use CRUD):
public class SharedDbMySQL : DatabaseMySQL
{
private static DatabaseMySQL sConn;
private SharedDbMySQL()
{
}
public static DatabaseMySQL GetInstance()
{
return GetInstance(TipoDados.Dados);
}
public static DatabaseMySQL GetInstance(TipoDados OpcoesBD)
{
if (sConn == null)
sConn = new DatabaseMySQL(OpcoesBD);
return sConn;
}
}
With the SQL(microsoft)... the error dont occours... only the Mysql.
We insert first the "NotaFiscalEntrada"...
After we insert the products of this "NotaFiscalEntrada" on this method(and we have the error here):
public static void InsereAtualizaNotaFiscalEntradaProduto(List<nf_entrada_produto> entity, int IDNFEntrada, bool SharedConnection, bool LastOperation)
{
DatabaseMySQL db;
MySqlCommand cmd = new MySqlCommand();
if (SharedConnection)
db = SharedDbMySQL.GetInstance();
else
db = new DatabaseMySQL();
try
{
cmd.Connection = db.Conn;
cmd.Transaction = db.BeginTransaction();
ONF_Entrada_Produto OpNFProduto = new ONF_Entrada_Produto(cmd);
foreach (nf_entrada_produto Item in entity)
{
Item.ValorICMSST = 0;
Item.IDNFEntrada = IDNFEntrada;
Item.IDEmpresa = BusinessLogicLayer.ObjetosGlobais.DadosGlobais.EmpresaGlobal.ID;
if (Item.ID == 0)
{
if (!OpNFProduto.Add(Item))
throw OpNFProduto.LastError;
}
else
{
if (!OpNFProduto.Update(Item))
throw OpNFProduto.LastError;
}
}
if (LastOperation || !SharedConnection)
{
db.CommitTransaction();
db.Disconnect();
}
}
catch (Exception ex)
{
db.RollBackTransaction();
db.Disconnect();
throw ex;
}
}
The error is when we insert the Products (code above)
"Lock wait timeout exceeded; try restarting transaction".
We found something about the deadlock... the lost of the connection can be the error, how to resolve it?I think thats a server error? thanks all.
The Problem was on the METHODS... I created again a new connection and not taking it from the singleton...
And the database deadlock the tables and other connections try to change it too... and there is the problems.
cmd.Connection = new db.Connect();
cmd.Connection = db.Conn;
replaced to
cmd.Connection = db.Conn;
Inside of class db(singleton):
MySqlConnection conn;
public MySqlConnection Conn
{
get
{
if ((conn == null) || (conn.State == System.Data.ConnectionState.Closed))
{
Connect();
}
return conn;
}
set
{
conn = value;
}
}
public override void Connect()
{
RetornaDadosIniParaClasse();
conn = new MySqlConnection(StringConnection);
try
{
conn.Open();
if (conn.State == System.Data.ConnectionState.Closed)
{
throw new AccessDatabaseException("Conexão com o banco de dados firebird fechada");
}
}
catch (Exception ex)
{
throw new AccessDatabaseException(ex.Message);
}
}
It taked a lot of time because its difficult to see the error... we debuged it a lot to find it.