SQLite insert command not works - c#

I don't understand why this insert statement not works. The debugging works fine and it returns "true". When I test it by SQLite Studio it works also.
(The ID is an integer and auto increments.) There are no errors.
public bool InsertInDB(string tForm, string tLang, string tKey, string tValue)
{
SqliteCommand cmd;
cmd = conn.CreateCommand();
try
{
if (string.IsNullOrEmpty(tForm)) { throw new NullReferenceException("Missing: tForm"); }
if (string.IsNullOrEmpty(tLang)) { throw new NullReferenceException("Missing: tLang"); }
string[] temp = tLang.Split('-');
if (temp.Length != 2) { throw new Exception("The language description is wrong. Form \"xx-xx\", ex.: \"en-US\""); }
if (string.IsNullOrEmpty(tKey)) { throw new NullReferenceException("Missing: tKey"); }
if (string.IsNullOrEmpty(tValue)) { throw new NullReferenceException("Missing: tValue"); }
cmd.Parameters.AddWithValue("#tForm", tForm);
cmd.Parameters.AddWithValue("#tLang", tLang);
cmd.Parameters.AddWithValue("#tKey", tKey);
cmd.Parameters.AddWithValue("#tValue", tValue);
cmd.CommandText = "INSERT INTO Translate (Form, Lang, Key, Value) VALUES (#tForm, #tLang, #tKey, #tValue)";
if (conn.State == System.Data.ConnectionState.Closed) { conn.Open(); }
var result = cmd.ExecuteNonQuery();
return (result > 0);
}
catch (SqliteException ex)
{
HandleException(ex, "InsertInDB");
}
catch (Exception ex)
{
HandleException(ex, "InsertInDB");
}
finally
{
if (conn.State == System.Data.ConnectionState.Open) { conn.Close(); }
}
return false;
}

Related

'Service1.InsertSupplier(Supplier)': not all code paths return a value

public int InsertSupplier(Supplier supplier)
{
try
{
comm.CommandText = "INSERT INTO SupplierTable(#sup_id, #Supplier_Name, #Address, #City, #Phone, #Email, #TIN)";
comm.Parameters.AddWithValue("sup_id", supplier.id);
comm.Parameters.AddWithValue("Supplier_Name", supplier.NameSupplier);
comm.Parameters.AddWithValue("Address", supplier.Address);
comm.Parameters.AddWithValue("City", supplier.City);
comm.Parameters.AddWithValue("Phone", supplier.Phone);
comm.Parameters.AddWithValue("Email", supplier.Email);
comm.Parameters.AddWithValue("TIN", supplier.TIN);
comm.CommandType = CommandType.Text;
conn.Open();
return comm.ExecuteNonQuery();
}
catch (Exception)
{
}
finally
{
if (conn != null)
{
conn.Close();
}
}
}
In case of exception occurence your method return without return.
Add something like return -1; at the end:
public int InsertSupplier(Supplier supplier)
{
try
{
// your code here
}
catch (Exception)
{
}
finally
{
if (conn != null)
{
conn.Close();
}
}
return -1; // or change this to more proper value
}

How can this database connection class be improved? (ADO.NET)

I am attempting to create a database access layer. I am looking for some improvements to this class/recommendations on best practice. It would be helpful if someone could point me to documentation on how this could be potentially done/things to consider. I have looked at using entity framework but it does not seem applicable, however, should I really be looking to move to EF? Is ADO.NET an outdated way of doing this?
public static IDbCommand GetCommandObject(string Connstring)
{
IDbConnection conn = new SqlConnection(Connstring);
return new SqlCommand { Connection = (SqlConnection)conn };
}
public static void AddParameter(ref IDbCommand cmd, string Name, object value, DbType ParamType)
{
IDbDataParameter Param = cmd.CreateParameter();
Param.DbType = ParamType;
Param.ParameterName = (Name.StartsWith("#")) ? "" : "#"; //# character for MS SQL database
Param.Value = value;
cmd.Parameters.Add(Param);
}
public static Int32 ExecuteNonQuery(string SQL, IDbCommand cmd = null)
{
Boolean CommitTrans = true;
Boolean CloseConn = true;
SqlTransaction Trans = null;
try
{
//IF Required - create command object if required
if (cmd == null) { cmd = DB.GetCommandObject(""); }
//Add the commandtext
cmd.CommandText = SQL;
if (cmd.Connection == null) { throw new Exception("No connection set"); }
//IF REQUIRED - open the connection
if (cmd.Connection.State == ConnectionState.Closed)
{
cmd.Connection.Open();
}
else
{
CloseConn = false;
}
if (cmd.Transaction != null)
{
//We have already been passed a Transaction so dont close it
CommitTrans = false;
}
else
{
//Create and open a new transaction
Trans = (SqlTransaction)cmd.Connection.BeginTransaction();
cmd.Transaction = Trans;
}
Int32 rtn = cmd.ExecuteNonQuery();
if (CommitTrans == true) { Trans.Commit(); }
return rtn;
}
catch (Exception e)
{
if (CommitTrans == true) { Trans.Rollback(); }
throw new Exception();
}
finally
{
if (CloseConn == true)
{
cmd.Connection.Close();
cmd = null;
}
}
}
public static object ExecuteScalar(string SQL, IDbCommand cmd, Boolean NeedsTransaction = true)
{
Boolean CommitTrans = true;
Boolean CloseConn = true;
SqlTransaction Trans = null;
try
{
//IF Required - create command object if required
if (cmd == null) { cmd = DB.GetCommandObject(""); }
//Add the commandtext
cmd.CommandText = SQL;
//IF REQUIRED - create default Connection to CourseBuilder DB
if (cmd.Connection == null) { throw new Exception("No Connection Object"); }
//IF REQUIRED - open the connection
if (cmd.Connection.State == ConnectionState.Closed)
{
cmd.Connection.Open();
}
else
{
CloseConn = false;
}
if (NeedsTransaction == true)
{
if (cmd.Transaction != null)
{
//We have already been passed a Transaction so dont close it
CommitTrans = false;
}
else
{
//Create and open a new transaction
Trans = (SqlTransaction)cmd.Connection.BeginTransaction();
cmd.Transaction = Trans;
}
}
Object rtn = cmd.ExecuteScalar();
if (NeedsTransaction == true && CommitTrans == true) { Trans.Commit(); }
return rtn;
}
catch
{
if (NeedsTransaction == true && Trans != null) { Trans.Rollback(); }
throw new Exception();
}
finally
{
if (CloseConn == true) { cmd.Connection.Close(); cmd = null; }
}
}
public static DataRow GetDataRow(string SQL, IDbCommand cmd = null, Boolean ErrorOnEmpty = true)
{
var dt = FillDatatable(SQL, ref cmd);
if (dt.Rows.Count > 0)
{
return dt.Rows[0];
}
else
{
if (ErrorOnEmpty == true) { throw new Exception(nameof(GetDataRow) + " returned no rows."); }
return null;
}
}
public static DataTable FillDatatable(string SQL, ref IDbCommand cmd)
{
string newline = System.Environment.NewLine;
var DT = new DataTable();
Boolean LeaveConOpen = false;
try
{
//Add the commandtext
cmd.CommandText = SQL;
//IF REQUIRED - create default Connection to CourseBuilder DB
if (cmd?.Connection == null) { throw new Exception("No Connection Object"); }
if (cmd.Connection.State != ConnectionState.Open)
{
cmd.Connection.Open();
LeaveConOpen = false;
}
else
{
LeaveConOpen = true;
}
var DA = new SqlDataAdapter((SqlCommand)cmd);
DA.Fill(DT);
}
catch (Exception ex)
{
var sbErr = new StringBuilder();
sbErr.AppendLine("Parameters (type defaults to varchar(max)):" + newline);
foreach (SqlParameter p in cmd.Parameters)
{
string s = "";
sbErr.AppendLine("declare " + p.ParameterName + " varchar(max) = '" + (p.Value == DBNull.Value ? "Null" : p.Value + "'; ") + newline);
}
sbErr.AppendLine(newline + SQL + newline);
throw new Exception("Failed to FillDataTable:" + newline + newline + sbErr.ToString(), ex);
}
finally
{
if (LeaveConOpen == false) { cmd.Connection.Close(); }
}
return DT;
}
public static T CheckNull<T>(T value, T DefaultValue)
{
if (value == null || value is System.DBNull)
{
return DefaultValue;
}
else
{
return value;
}
}
Couple of things to keep in mind when you are creating a DAL
DAL should be able to cater to multiple Databases (oracle , sql , mysql etc..)
You should have minimum of DB , Connection , Command and Reader implementations of each.
Do not worry about the connection pool
Be aware of the transaction scope , Especially when you are trying to save nested objects. (For Eg: by saving company, you are saving Company and Company.Employees and Employee.Phones in a single transaction)
Alternative is to use something like Dapper.
enter image description here

System.ArgumentException Value does not fall within the expected range, SQL issue

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);

Not all code paths return a value - error

I have the following code to read if data exist. I want to return true or false but C# compiler says: "not all code paths return a value" and red error line shown on my method name ReadDV.
The code is:
public bool ReadDV(string ReadCommand)
{
try
{
SqlConnection SCO = ConnectionClass.getconnection();
SqlCommand delCmd = new SqlCommand(ReadCommand, SCO);
if (SCO.State != ConnectionState.Open)
SCO.Open();
SqlDataReader r = delCmd.ExecuteReader();
if (r.Read())
{
if (SCO.State != ConnectionState.Closed)
SCO.Close();
r.Close();
return true;
}
}
catch (Exception ex)
{
return false;
}
}
The ConnectionClass.getconnection() code is a part of a method for returning the connection string and it is working ok.
I will add 2nd part of my code for calling this method : it doesn't work when read is null
string RUSERSSV = #"select * from USERSSV where Users = ........;
DB db = new DB(); // calling method
if (comboBox1.Text != "")
{
if (db.ReadDV(RUSERSSV)==true) // this is the mention part
{
string IUSERSSV = #"update USERSSV set Users = // insert fired if read is true
db.insert(IUSERSSV);
Save.Form(this);
}
else
{
string IUSERSSV = #"insert into USERSSV // update fired if read false
db.insert(IUSERSSV);
Save.Form(this);
}
You have return statement in if that may or may not execute you should have one return statement that must execute. Putting return after catch will probably remove the error if it get executed unconditionally. You can use a bool variable to store the value to return and return that variable.
bool success = false;
try
{
SqlConnection SCO = ConnectionClass.getconnection();
SqlCommand delCmd = new SqlCommand(ReadCommand, SCO);
if (SCO.State != ConnectionState.Open) SCO.Open();
SqlDataReader r = delCmd.ExecuteReader();
if (r.Read())
{
if (SCO.State != ConnectionState.Closed) SCO.Close();
r.Close();
success = true;
}
}
catch (Exception ex)
{
return false;
}
return success;
Place the return statement outside the if( r.Read() ) block
if (r.Read())
{
if (SCO.State != ConnectionState.Closed) SCO.Close();
r.Close();
}
// other code
return true;
Basically, there should be a return statement right before your function ends.
Your code isn't returning anything, when if(r.Read()) is false.
You could fix your code following way:
public bool ReadDV(string ReadCommand)
{
bool returnValue = false;
try
{
SqlConnection SCO = ConnectionClass.getconnection();
SqlCommand delCmd = new SqlCommand(ReadCommand, SCO);
if (SCO.State != ConnectionState.Open) SCO.Open();
SqlDataReader r = delCmd.ExecuteReader();
if (r.Read())
{
if (SCO.State != ConnectionState.Closed) SCO.Close();
r.Close();
returnValue = true;
}
}
catch (Exception ex)
{
returnValue = false;
}
return returnValue;
}
Above code now always returns false, when r.Read was false or an exception was catched.
I propose this, it's a cleaner solution and it'll prevent issues like the yours:
public bool ReadDV(string ReadCommand)
{
bool result = false;
try
{
SqlConnection SCO = ConnectionClass.getconnection();
SqlCommand delCmd = new SqlCommand(ReadCommand, SCO);
if (SCO.State != ConnectionState.Open) SCO.Open();
SqlDataReader r = delCmd.ExecuteReader();
if (r.Read())
{
if (SCO.State != ConnectionState.Closed) SCO.Close();
r.Close();
result = true;
}
}
catch (Exception ex)
{
result = false;
}
return result;
}
public bool ReadDV(string ReadCommand)
{
bool bRetVal = false;
try
{
SqlConnection SCO = ConnectionClass.getconnection();
SqlCommand delCmd = new SqlCommand(ReadCommand, SCO);
if (SCO.State != ConnectionState.Open) SCO.Open();
SqlDataReader r = delCmd.ExecuteReader();
if (r.Read())
{
if (SCO.State != ConnectionState.Closed) SCO.Close();
r.Close();
bRetVal = true;
}
}
catch (Exception ex)
{
bRetVal = false;
}
return bRetVal
}
Try to initialize the return values in a variable and then change the value depending on your code path and just have one return statement in the end, that way you dont need to have multiple return statements. (The error is because you missed return statement for that function - Every possible code path should return a value for that function)
thanks all
I made it with following :
public bool ReadDV(string ReadCommand)
{
bool result = false;
try
{
SqlConnection SCO = ConnectionClass.getconnection();
SqlCommand delCmd = new SqlCommand(ReadCommand, SCO);
if (SCO.State != ConnectionState.Open) SCO.Open();
SqlDataReader r = delCmd.ExecuteReader();
if (r.Read()==true)
{
if (SCO.State != ConnectionState.Closed) SCO.Close();
r.Close();
result = true;
}
else if (r.Read() == false)
{
if (SCO.State != ConnectionState.Closed) SCO.Close();
r.Close();
result = false;
}
}
catch (Exception ex)
{
result = false;
}
return result;
}

DeadLock on Mysql using C# - "Lock wait timeout exceeded; try restarting transaction"

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.

Categories

Resources