I'm working on an android app to be deployed in a warehouse, and I'm having issues accessing the SQL database on the 192.168.8.* network. It works fine in debug, but when I come to deploying it in the release it is unable to make the connection.
As it's all internal I'm directly running queries on the SQL as opposed to creating a service layer.
Any pointers would be very much appreciated.
My connection string is like so
Server={0};Database=Database;User Id={1};Password={2};Connection Timeout=10;
Code:
public static string ReturnString(string query, string expectedDataType =
"STRING")
{
SqlConnection connection = null;
try
{
using (connection = new SqlConnection(GetConnectionString()))
{
//open connection
connection.Open();
SqlCommand command = new SqlCommand(query, connection);
command.Connection = connection;
command.CommandText = query;
var result = command.ExecuteScalar();
//close connection
connection.Close();
//see if there is a table to return
if (expectedDataType == "INT" && (result == System.DBNull.Value || result == null))
{
return "0";
}
if (result != "" && (result != null && result != System.DBNull.Value))
{
return result.ToString();
}
}
}
catch (Exception exception)
{
#region connection error
Console.Write("ERROR IS HERE: " + exception);
#endregion
}
finally
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
}
return null;
}
Related
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
When ExecuteNonQuery(), my database gets locked but if I comment that part ExecuteReader works fine. How to avoid database getting locked? I know that first is a write into database when creating indexes and the second time is reading but there are cases when this code below works fine. I need that index to be created to gain speed. There are a lot of functions created this way to get the data from the database (which is a .rdb file) and there are times that some of them are not working
List<TargetedOutputRDB1> entityList = new List<TargetedOutputRDB1>();
//
DbDataReader reader = null;
SimulationRDB1 simulation = (SimulationRDB1)crash.Simulation;
DbConnection dbConnection = ((RDB1Connection)crash.DbConnection).DbProviderFactory.CreateConnection();
dbConnection.ConnectionString = crash.DbConnection.ConnectionString;
bool connectionWasClosed = (dbConnection.State == ConnectionState.Closed);
//
try
{
DbCommand dbCommand = dbConnection.CreateCommand();
dbCommand.Transaction = (((RDB1Connection)simulation.DbConnection).DbTransaction != null && ((RDB1Connection)simulation.DbConnection).DbTransaction.Connection == simulation.DbConnection ? ((RDB1Connection)simulation.DbConnection).DbTransaction : null); //must be set!
//
if (dbConnection.State == ConnectionState.Closed)
dbConnection.Open();
//
dbCommand.CommandText = string.Format("CREATE INDEX IF NOT EXISTS TOIndexSC ON TargetedOutputs (SimulationId, CrashId)");
dbCommand.ExecuteNonQuery();
dbCommand.CommandText = string.Format("SELECT * FROM TargetedOutputs WHERE SimulationId={0} AND CrashId={1}", ((SimulationRDB1)crash.Simulation).ID, crash.ID);
reader = dbCommand.ExecuteReader();
//
while (reader.Read())
{
long id = (long)reader["Id"];
TargetedOutputRDB1 entity = new TargetedOutputRDB1(simulation, id, reader, false);
entityList.Add(entity);
}
//
return entityList.ToArray();
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (reader != null)
reader.Close();
//
if (connectionWasClosed)
dbConnection.Close();
//dbConnection.Dispose();
}
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;
}
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.
I want to write a small application in Winforms, where I will be able to write some words and write them to a SQL database using ADO.net.
I'm having trouble when I want to write a string with a placeholder like:
Give me your '%s' right now!
What is recorded in my DB is:
Give me your **"%s"** right now!
How can I overcome this be changing the string via C# that is transferred to my DB?
This is part of my code:
public virtual int Split(global::System.Nullable<int> ID, object SplitXMLDoc, string CreatedBy)
{
global::System.Data.SqlClient.SqlCommand command = this.CommandCollection[4];
if ((ID.HasValue == true)) {
command.Parameters[1].Value = ((int)(ID.Value));
}
else {
command.Parameters[1].Value = global::System.DBNull.Value;
}
if ((SplitXMLDoc == null)) {
command.Parameters[2].Value = global::System.DBNull.Value;
}
else {
command.Parameters[2].Value = ((object)(SplitXMLDoc));
}
if ((CreatedBy == null)) {
command.Parameters[3].Value = global::System.DBNull.Value;
}
else {
command.Parameters[3].Value = ((string)(CreatedBy));
}
global::System.Data.ConnectionState previousConnectionState = command.Connection.State;
if (((command.Connection.State & global::System.Data.ConnectionState.Open)
!= global::System.Data.ConnectionState.Open)) {
command.Connection.Open();
}
int returnValue;
try {
returnValue = command.ExecuteNonQuery();
}
finally {
if ((previousConnectionState == global::System.Data.ConnectionState.Closed))
{
command.Connection.Close();
}
}
return returnValue;
}
You use parameterized sql.
string val = "'%s'".Replace("'","\"");
string sql = "INSERT Into Table1 (value) values (#Value)";
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.Parameters.AddWithValue("#Value",val);
cmd.ExecuteNonQuery();