Create separate class for connection string - c#

i am trying to create separate class for connection named Connection.cs, why am i having this error while executing the query
ExecuteNonQuery requires an open and available Connection. The connection's current state is closed
what am i doing wrong ?
in my Dal.cs class
public void Insert(string f1,string f2)
{
string query;
Connection c = new Connection();
c.OpenCnn();
try {
query = "inset into ..."
cmd = new SqlCommand(query, con);
cmd.ExecuteNonQuery();
}
catch (Exception ex){
throw ex;
}
finally {
c.CloseCnn();
}
}
and in my Connection.cs class
public class Connection
{
SqlCommand cmd = new SqlCommand();
SqlConnection con = new SqlConnection();
public void OpenCnn()
{
string cnnStr = ConfigurationManager.ConnectionStrings["myconnstrng"].ToString();
con = new SqlConnection(cnnStr);
con.Open();
}
public void CloseCnn()
{
con.Close();
}
}

Currently the con field is private and can not be accessible from outside of Connection class.
You can add a property to your connection class:
public SqlConnection Connection { get { return con; } }
Then access it via your instance:
Connection c = new Connection();
c.OpenCnn();
try
{
query = "inset into ..."
cmd = new SqlCommand(query, c.Connection);
cmd.ExecuteNonQuery();
}
Btw, I'm not sure what are you referring by con in your Insert method (probably a local variable instead of the con field, because otherwise it wouldn't even compile)

public class Connection
{
SqlConnection con;
public SqlConnection Conn { get { return con; } }
public void OpenCnn()
{
string cnnStr = ConfigurationManager.ConnectionStrings["myconnstrng"].ToString();
con = new SqlConnection(cnnStr);
con.Open();
}
public void CloseCnn()
{
con.Close();
}
}
Method Insert:
Note SqlCommand initialization and usage of public property conn.
public void Insert(string f1, string f2)
{
string query;
Connection c = new Connection();
c.OpenCnn();
try
{
query = "insert into ..."
SqlCommand cmd = new SqlCommand(query, c.Conn);
cmd.ExecuteNonQuery();
}
catch (Exception ex){
throw ex;
}
finally {
c.CloseCnn();
}
}

Related

Syntax error on SQLite Alter Table with Finisar.SQLite in C#

I want to create columns through C# code.
I have tried this code:
string query = "Alter Table CompanyMaster ADD COLUMN CompanyType TEXT";
DbConnection.ExecuteNonQuery(query);
DbConnection.ExecuteNonQuery class code is :
// Class variables declared elsewhere...
private static SQLiteConnection sqlConnection;
private static SQLiteCommand sqlCmd;
private static SQLiteDataAdapter sqlAdt;
Public static int ExecuteNonQuery(string query)
{
try
{
if (sqlConnection.State == ConnectionState.Closed)
sqlConnection.Open();
sqlCmd = sqlConnection.CreateCommand();
sqlCmd.CommandText = query;
Thread.Sleep(5);
return sqlCmd.ExecuteNonQuery();
}
catch (Exception)
{
throw;
// return 0;
}
finally
{
...
}
}
I got catch throw error
Finisar.SQLite.SQLiteException: 'near "Alter": syntax error'

Fill: SelectCommand.Connection error on derived iDBCommand

Before you dowonvote this, please have a look first. I know there numerous threads here with this errormessage, but I haven't found one with this particular problem. I've created a custom command class implementing the IDbCommand interface like this:
internal class Prozedur : IDbCommand
{
private static SqlCommand command = new SqlCommand() ;
private SqlConnection connection;
string commandtext;
CommandType commandType;
public Prozedur(string abfrage)
{
commandtext = abfrage;
commandType = CommandType.StoredProcedure;
connection = (SqlConnection)new Verbindung();
SqlCommand command = new SqlCommand(commandtext, connection);
}
public static explicit operator SqlCommand(Prozedur v)
{
return command;
}
...
I'am using the object like this:
internal class Tabelle : DataTable
{
DataTable tabelle = new DataTable();
internal Tabelle(string abfrage)
{
Prozedur p = new Prozedur(abfrage);
SqlDataAdapter adapter = new SqlDataAdapter((SqlCommand)p);
adapter.Fill(tabelle);
}
}
However, on the adapter.Fill(tabelle) i get the Error “Fill: SelectCommand.Connection property has not been initialized.”. But if i look at the object p, the connection is there:
Update
If i change the code like this
internal class Tabelle : DataTable
{
DataTable tabelle = new DataTable();
internal Tabelle(string abfrage)
{
Prozedur p = new Prozedur(abfrage);
SqlCommand c = (SqlCommand)p;
//added this line
c.Connection = p.Connection;
SqlDataAdapter adapter = new SqlDataAdapter((SqlCommand)p);
adapter.Fill(tabelle);
}
}
I get a compiler error for p.Connection; C# Cannot implicitly convert type to. An explicit conversion exists (are you missing a cast?).
The code for the connection is this:
public IDbConnection Connection
{
get
{
return connection;
}
set
{
connection = (SqlConnection)value;
}
}
The problem was in the convert method. When I change the code as below it works. Basically I had to make all variables static and return a new SqlCommandObject in the convert method.
internal class Prozedur : IDbCommand
{
private static SqlCommand command = new SqlCommand();
private static SqlConnection connection;
static string commandtext;
CommandType commandType;
public Prozedur(string abfrage)
{
commandtext = abfrage;
commandType = CommandType.StoredProcedure;
connection = (SqlConnection)new Verbindung();
}
public static explicit operator SqlCommand(Prozedur v)
{
return new SqlCommand() { CommandText = commandtext, Connection = connection, CommandType = command.CommandType };
}
...
And it works like this without static variables:
internal class Prozedur : IDbCommand
{
private SqlCommand command = new SqlCommand();
private SqlConnection connection;
string commandtext;
CommandType commandType;
public Prozedur(string abfrage)
{
commandtext = abfrage;
commandType = CommandType.StoredProcedure;
connection = (SqlConnection)new Verbindung();
}
public static explicit operator SqlCommand(Prozedur v)
{
return new SqlCommand() { CommandText = v.CommandText, Connection = (SqlConnection)v.Connection, CommandType = v.CommandType };
}
...

Update Collection Value with Database in UWP(MVVM)

I have custom collection which contains student_id,student_name,student_mark.And having the table with same columns in the database as well. The design form have some controls for updating the existing student.
Temporarily all the updating operations are done with that custom collection.Lets assume we have 100 students data in collection and database. Any updating operation should reflect in the collection. But what my doubt is how do i update these values with the database before i close the application??
But when i open the application the collection should have all the values which have stored in the database.
But what my doubt is how do i update these values with the database
Firstly, you need to know how to do CRUD operations on MySQL database with uwp app. For this, please reference this sample.
Secondly, according to your description, you have built up a MVVM project to bind a collection data to the view. But you didn't have a data layer for this MVVM structure. For this, you need to create a class for data layer to do GRUD operations, and establish contact with this data service from ViewModel. More details please reference this article.
The class for data layer I wrote according to your description which contains how to read, update and delete data from mysql database is as follows:
public class Student
{
public int Student_id { get; set; }
public string Student_name { get; set; }
public string Student_mark { get; set; }
}
public class DataService
{
static string connectionString;
public static String Name = "Data Service.";
private static ObservableCollection<Student> _allStudents = new ObservableCollection<Student>();
public static ObservableCollection<Student> GetStudents()
{
try
{
string server = "127.0.0.1";
string database = "sakila";
string user = "root";
string pswd = "!QAZ2wsx";
connectionString = "Server = " + server + ";database = " + database + ";uid = " + user + ";password = " + pswd + ";SslMode=None;";
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
MySqlCommand getCommand = connection.CreateCommand();
getCommand.CommandText = "SELECT * FROM student";
using (MySqlDataReader reader = getCommand.ExecuteReader())
{
while (reader.Read())
{
_allStudents.Add(new Student() { Student_id = reader.GetInt32(0), Student_name = reader.GetString(1), Student_mark = reader.GetString(2) });
}
}
}
}
catch (MySqlException sqlex)
{
// Handle it :)
}
return _allStudents;
}
public static bool InsertNewStudent(Student newStudent)
{
// Insert to the collection and update DB
try
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
MySqlCommand insertCommand = connection.CreateCommand();
insertCommand.CommandText = "INSERT INTO student(student_id, student_name, student_mark)VALUES(#student_id, #student_name,#student_mark)";
insertCommand.Parameters.AddWithValue("#student_id", newStudent.Student_id);
insertCommand.Parameters.AddWithValue("#student_name", newStudent.Student_name);
insertCommand.Parameters.AddWithValue("#student_mark", newStudent.Student_mark);
insertCommand.ExecuteNonQuery();
return true;
}
}
catch (MySqlException sqlex)
{
return false;
}
}
public static bool UpdateStudent(Student Student)
{
try
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
MySqlCommand insertCommand = connection.CreateCommand();
insertCommand.CommandText = "Update student Set student_name= #student_name, student_mark=#student_mark Where student_id =#student_id";
insertCommand.Parameters.AddWithValue("#student_id", Student.Student_id);
insertCommand.Parameters.AddWithValue("#student_name", Student.Student_name);
insertCommand.Parameters.AddWithValue("#student_mark", Student.Student_mark);
insertCommand.ExecuteNonQuery();
return true;
}
}
catch (MySqlException sqlex)
{
// Don't forget to handle it
return false;
}
}
public static bool Delete(Student Student)
{
try
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
MySqlCommand insertCommand = connection.CreateCommand();
insertCommand.CommandText = "Delete from sakila.student where student_id =#student_id";
insertCommand.Parameters.AddWithValue("#student_id", Student.Student_id);
insertCommand.ExecuteNonQuery();
return true;
}
}
catch (MySqlException sqlex)
{
return false;
}
}
}
For updating the database in TwoWay binding way, we can implement is by invoking the data updating method in
PropertyChanged event as follows:
void Person_OnNotifyPropertyChanged(Object sender, PropertyChangedEventArgs e)
{
organization.Update((StudentViewModel)sender);
}
For the completed demo you can download here.

ADO.NET DAL and BLL

I have two classes SqlHelper and DishesTypes there are used in a DAL project
public class SqlHelper
{
public static SqlDataReader ExecuteReader(string procedure,
params SqlParameter[] commandParameters)
{
using (var connection = new SqlConnection(
ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
using (var command = new SqlCommand(procedure, _connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(commandParameters);
return command.ExecuteReader();
}
}
public class DishesTypes
{
public static SqlDataReader DishesTypesSelectAll()
{
return SqlHelper.ExecuteReader("DishesTypesSelectAllRows"); //name of procedure
}
}
And I have class DishedTypes that used in a BLL project like this
public class DishesTypes
{
public int DishTypeId { get; set; }
public string DishType { get; set; }
public static List<DishesTypes> DishesTypesSelectAll()
{
IDataReader dr = DataAccessLayer.DishesTypes.DishesTypesSelectAll();
List<DishesTypes> dishesTypesList = new List<DishesTypes>();
while (dr.Read())
{
DishesTypes myDishesTypes = new DishesTypes
{
DishTypeId = (int)dr["DishTypeId"],
DishType = (string)dr["DishType"]
};
dishesTypesList.Add(myDishesTypes);
}
return dishesTypesList;
}
}
Problems starts here while (dr.Read()),The reason, the connection to this point has already closed and it is necessary to reconnect how best to change the implementation of classes adhering layers DAL and BLL, to work?
If you want to roll your own, something like this is better:
public class DataQuery
{
private readonly string _connectionString;
public DataQuery(string connectionString)
{
_connectionString = connectionString;
}
public IEnumerable<T> GetList<T>(string procedure,
Func<IDataRecord, T> entityCreator,
params SqlParameter[] commandParameters
)
{
var result = new List<T>();
using (var connection = CreateConnection())
using (var command = CreateCommand(procedure, connection, commandParameters))
using (var reader = command.ExecuteReader())
{
result.Add(entityCreator(reader));
}
return result;
}
private SqlConnection CreateConnection()
{
var connection = new SqlConnection(_connectionString);
connection.Open();
return connection;
}
private static DbCommand CreateCommand(string procedure,
SqlConnection connection, SqlParameter[] commandParameters)
{
var command = new SqlCommand(procedure, connection)
{
CommandType = CommandType.StoredProcedure
};
command.Parameters.AddRange(commandParameters);
return command;
}
}
Which you would call like this:
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"]
.ConnectionString;
var query = new DataQuery(connectionString);
Func<IDataRecord, DishesTypes> creator = dr =>
new DishesTypes
{
DishTypeId = (int)dr["DishTypeId"],
DishType = (string)dr["DishType"]
};
var results = query.GetList("DishesTypesSelectAllRows", creator);
Otherwise, which I recommend, have a look at Dapper.
Dapper would allow you to simply do:
var results = connection.Query<DishesTypes>("DishesTypesSelectAllRows",
commandType: CommandType.StoredProcedure);
First of all, your using statement is closing your connection, so you cannot expect to return a useable IDataReader. Second, your connection is never opened, so you would not get a result, anyway. Having said that, if your dataset will always be small enough to fit in memory, you could use something like what I have done below. This should have minimal impact on your code.
public class SqlHelper
{
public static IDataReader ExecuteReader(string procedure, params SqlParameter[] commandParameters)
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
connection.Open();
using (var command = new SqlCommand(procedure, connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(commandParameters);
DataTable dt = new DataTable();
using (SqlDataAdapter da = new SqlDataAdapter(command))
da.Fill(dt);
return dt.CreateDataReader();
}
}
}
}
public class DishesTypes
{
public static IDataReader DishesTypesSelectAll()
{
return SqlHelper.ExecuteReader("DishesTypesSelectAllRows");//name of procedure
}
}

Call multiple SQL Server stored procedures in a transaction

For usage in my current project I've created a class that allows me to call SQL Server async.
My code looks like this:
internal class CommandAndCallback<TCallback, TError>
{
public SqlCommand Sql { get; set; }
public TCallback Callback { get; set; }
public TError Error { get; set; }
}
class MyCodes:SingletonBase<MyCodes>
{
private static string _connString = #"Data Source=MyDB;Initial Catalog=ED;Integrated Security=True;Asynchronous Processing=true;Connection Timeout=0;Application Name=TEST";
private MyCodes() { }
public void SetSystem(bool production)
{
_connString =
string.Format(#"Data Source=MyDB;Initial Catalog={0};Integrated Security=True;Asynchronous Processing=true;Connection Timeout=0;Application Name=TEST", production ? "ED" : "TEST_ED");
}
public void Add(string newCode, Action<int> callback, Action<string> error)
{
var conn = new SqlConnection(_connString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = #"ADD_CODE";
cmd.Parameters.Add("#NEW", SqlDbType.NVarChar).Value = newCode;
cmd.Parameters.Add("#NewId", SqlDbType.Int).Direction = ParameterDirection.Output;
try
{
cmd.Connection.Open();
}
catch (Exception ex)
{
error(ex.ToString());
return;
}
var ar = new CommandAndCallback<Action<int>, Action<string>> { Callback = callback, Error = error, Sql = cmd };
cmd.BeginExecuteReader(Add_Handler, ar, CommandBehavior.CloseConnection);
}
private static void Add_Handler(IAsyncResult result)
{
var ar = (CommandAndCallback<Action<int>, Action<string>>)result.AsyncState;
if (result.IsCompleted)
{
try
{
ar.Sql.EndExecuteReader(result);
ar.Callback(Convert.ToInt32(ar.Sql.Parameters["#NewId"].Value));
}
catch (Exception ex)
{
ar.Error(ex.Message);
}
}
else
{
ar.Error("Error executing SQL");
}
}
public void Update(int codeId, string newCode, Action callback, Action<string> error)
{
var conn = new SqlConnection(_connString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = #"UPDATE_CODE";
cmd.Parameters.Add("#CODE_ID", SqlDbType.Int).Value = codeId;
cmd.Parameters.Add("#NEW", SqlDbType.NVarChar).Value = newCode;
try
{
cmd.Connection.Open();
}
catch (Exception ex)
{
error(ex.ToString());
return;
}
var ar = new CommandAndCallback<Action, Action<string>> { Callback = callback, Error = error, Sql = cmd };
cmd.BeginExecuteReader(Update_Handler, ar, CommandBehavior.CloseConnection);
}
private static void Update_Handler(IAsyncResult result)
{
var ar = (CommandAndCallback<Action, Action<string>>)result.AsyncState;
if (result.IsCompleted)
{
try
{
ar.Sql.EndExecuteReader(result);
ar.Callback();
}
catch (Exception ex)
{
ar.Error(ex.Message);
}
}
else
{
ar.Error("Error executing SQL");
}
}
}
This may look like too much of code, but it lets me call it as so:
private void Add_Click(object sender, EventArgs e)
{
MyCodes.Instance.Add("Test",Success,Error)
}
private void Success(int newId)
{
MessageBox.Show(newId.ToString(), "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void Error(string error)
{
MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Above code works just fine for me, I'm able to do every call async.
Problem that I have right now is to do multiple calls as transaction - I would like to update 2 codes and add one new.
Normally I would call update, then in success handler call second update, and in handler to second update I would call add that would return new id.
Something like:
-UPDATE CODE
|-UPDATE CODE
|-ADD CODE (only this one return something)
But I would like to call all of those as transaction, so if add code would break updates would rollback.
Question:
Is it possible to call multiple async queries as a transaction?
Can I call my above methods as transaction or do I must create separate method to call my procedures as one? (I would like to avoid this one because it's just copying the same code from one method to another)
I would like to add that I use .NET 3.5 so await and other nice features aren't an option.
string cnnString =WebConfigurationManager.ConnectionStrings["MyString"].ConnectionString;
SqlConnection cnn = new SqlConnection(cnnString);
SqlTransaction transaction;
cnn.Open();
transaction = cnn.BeginTransaction();
try
{
// Command Objects for the transaction
SqlCommand cmd1 = new SqlCommand("sproc1", cnn);
SqlCommand cmd2 = new SqlCommand("sproc2", cnn);
cmd1.CommandType = CommandType.StoredProcedure;
cmd2.CommandType = CommandType.StoredProcedure;
cmd1.Parameters.Add(new SqlParameter("#Param1", SqlDbType.NVarChar, 50));
cmd1.Parameters["#Param1"].Value = paramValue1;
cmd1.Parameters.Add(new SqlParameter("#Param2", SqlDbType.NVarChar, 50));
cmd1.Parameters["#Param2"].Value = paramValue2;
cmd2.Parameters.Add(new SqlParameter("#Param3", SqlDbType.NVarChar, 50));
cmd2.Parameters["#Param3"].Value = paramValue3;
cmd2.Parameters.Add(new SqlParameter("#Param4", SqlDbType.NVarChar, 50));
cmd2.Parameters["#Param4"].Value = paramValue4;
cmd1.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
transaction.Commit();
}
catch (SqlException sqlEx)
{
transaction.Rollback();
}
finally
{
cnn.Close();
cnn.Dispose();
}
Yes, it is possible. Simply call SqlConnection.BeginTransaction before your first call. Make sure you assign the returned SqlTransaction object to each SqlCommand.Transaction in the chain and call SqlTransaction.Commit() at the end.
public class Command
{
public string sql { get; set; }
public CommandType cmdType { get; set; }
public Dictionary<string, object> parameter { get; set; } = null;
}
private Command insertInvoice(Invoice invoice)
{
try
{
Dictionary<string, object> parameterLocal = new Dictionary<string, object>();
parameterLocal.Add("p_customerId", invoice.customerId);
parameterLocal.Add("p_invoiceNo", invoice.invoiceNo);
parameterLocal.Add("p_invoiceDate", invoice.invoiceDate);
parameterLocal.Add("p_invoiceAmount", invoice.invoiceAmount);
parameterLocal.Add("p_withInvoice", invoice.withInvoice);
return (new Command { sql = "sp_insertInvoice", cmdType = CommandType.StoredProcedure, parameter = parameterLocal });
}
catch (Exception ex)
{
throw ex;
}
}
private Command insertInvoiceModel(InvoiceModel invoiceModel)
{
try
{
Dictionary<string, object> parameterLocal = new Dictionary<string, object>();
parameterLocal.Add("p_invoiceNo", invoiceModel.invoiceNo);
parameterLocal.Add("p_model", invoiceModel.model);
parameterLocal.Add("p_quantity", invoiceModel.quantity);
parameterLocal.Add("p_unitPrice", invoiceModel.unitPrice);
return (new Command { sql = "sp_insertInvoiceModel", cmdType = CommandType.StoredProcedure, parameter = parameterLocal });
}
catch (Exception ex)
{
throw ex;
}
}
List<Command> commandList = new List<Command>();
cmd = insertInvoice(invoicesave);
commandList.Add(cmd);
cmd = insertInvoiceModel(invoiceModelSave);
commandList.Add(cmd);
try
{
erplibmain.erpDac.runOleDbTransaction(commandList);
}
catch (Exception ex)
{
throw ex;
}
public void runOleDbTransaction(List<Command> commandList)
{
OleDbConnection erpConnection = new OleDbConnection(ErpDalMain.connectionstring);
erpConnection.Open();
OleDbCommand erpCommand = erpConnection.CreateCommand();
OleDbTransaction erpTrans;
// Start a local transaction
erpTrans = erpConnection.BeginTransaction();
// Assign transaction object for a pending local transaction
erpCommand.Connection = erpConnection;
erpCommand.Transaction = erpTrans;
try
{
foreach (Command cmd in commandList)
{
erpCommand.CommandText = cmd.sql;
erpCommand.CommandType = cmd.cmdType;
foreach (KeyValuePair<string, object> entry in cmd.parameter)
{
erpCommand.Parameters.AddWithValue(entry.Key, entry.Value);
}
erpCommand.ExecuteNonQuery();
erpCommand.Parameters.Clear();
}
erpTrans.Commit();
}
catch (Exception e)
{
try
{
erpTrans.Rollback();
}
catch (OleDbException ex)
{
if (erpTrans.Connection != null)
{
throw ex;
}
}
throw e;
}
finally
{
erpConnection.Close();
}
}

Categories