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
Related
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;
}
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;
}
I have bit of code in my program that will not let and operator start another batch until they finish the one that they are on but still allows another operator to start the same batch. The sqldatareader is returning the correct data i.e. 17080387-002 but the program keeps going to the "Please finish batch" step. I'm trying to figure out if it possibly has anything to do with how the batch is being returned.
public void BatchLockOut()
{
string eventID = null;
string batchLock = null;
string enteredLot = TextBoxLot.Text;
string connectionString = "";
string commandText = "SELECT BadgeNo, Container_ID, Event_ID, Event_Time " +
"FROM dbo.Custom_EventLog " +
"WHERE Event_Time IN (SELECT MAX(Event_Time) FROM dbo.Custom_EventLog WHERE BadgeNo = #BADGENO)";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(commandText, connection))
{
command.Parameters.Add("#BADGENO", SqlDbType.NChar, 10).Value = TextBoxLogin.Text;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
eventID = Convert.ToInt32(reader["Event_ID"]).ToString();
batchLock = reader["Container_ID"] as string;
break;
}
}
connection.Close();
}
if (batchLock == null)
{
ButtonBeginStir.IsEnabled = true;
}
else if (batchLock != enteredLot)
{
if (eventID == "1")
{
MessageBox.Show("Please finish previous stir", "Finish Stir", MessageBoxButton.OK, MessageBoxImage.Information);
ClearForm();
}
else
{
ButtonBeginStir.IsEnabled = true;
}
}
else if (batchLock == enteredLot)
{
if (eventID == "1")
{
ButtonEndStir.IsEnabled = true;
}
else if (eventID == "2")
{
ButtonBeginStir.IsEnabled = true;
}
}
}
Can somebody help understand this code?
protected void Page_Load(object sender, EventArgs e)
{
Database database = new Database();
OleDbConnection conn = database.connectDatabase();
if (Request.Cookies["BesteldeArtikelen"] == null)
{
lbl_leeg.Text = "Er zijn nog geen bestelde artikelen";
}
else
{
HttpCookie best = Request.Cookies["BesteldeArtikelen"];
int aantal_bestel = best.Values.AllKeys.Length;
int[] bestelde = new int[aantal_bestel];
int index = 0;
foreach (string art_id in best.Values.AllKeys)
{
int aantalbesteld = int.Parse(aantalVoorArtikel(int.Parse(art_id)));
int artikel_id = int.Parse(art_id); // moet getalletje zijn
if (aantalbesteld != 0)
{
bestelde[index] = artikel_id;
}
index++;
}
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT artikel_id, naam, prijs, vegetarische FROM artikel WHERE artikel_id IN (" +
String.Join(", ", bestelde) + ")";
try
{
conn.Open();
OleDbDataReader reader = cmd.ExecuteReader();
GridView1.DataSource = reader;
GridView1.DataBind();
}
catch (Exception error)
{
errorMessage.Text = error.ToString();
}
finally
{
conn.Close();
}
}
}
And there is this part of code i dont really understand:
public string aantalVoorArtikel(object id)
{
int artikel_id = (int)id;
if (Request.Cookies["BesteldeArtikelen"] != null &&
Request.Cookies["BesteldeArtikelen"][artikel_id.ToString()] != null)
{
return Request.Cookies["BesteldeArtikelen"][artikel_id.ToString()];
}
else
{
return "0";
}
}
It extracts values from a cookie and builds an int array. (Displays a message if the cookie value is null) The int array is then used as the value for the SQL IN operator when querying the database. The result set is then bound to the GridView.
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;
}