I am having a function which calls different functions that connect to the mysql database and queries the database. Here I am not sure how can I reuse my conn and cmd to make more efficiency in the code. To have the connection creaeted in Validation() once and reuse them in the other function wherever I am trying to connect to database. Below is what I am doing
private static void Validation(List<Employee> EmpList, string Group)
{
ValidateName(EmpList, Group);
ValidateDept(EmpList, Group);
}
public static void ValidateName(List<Employee> EmpList, string Grp)
{
var connStr = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
string selectQuery;
for (int i = 0; i < EmpList.Count; i++)
{
selectQuery = "Select Name from Employee where Group = #Group AND #Name in (FirstName, LastName);";
using (MySqlConnection conn = new MySqlConnection(connStr))
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
cmd.Parameters.Add("#Group", MySqlDbType.VarChar).Value = Grp;
cmd.Parameters.Add("#Name", MySqlDbType.VarChar).Value = EmpList[i].Name;
conn.Open();
var reader = cmd.ExecuteReader();
List<string> lineList = new List<string>();
while (reader.Read())
{
lineList.Add(reader.GetString(0));
}
if (lineList.Count <=0)
{
WriteValidationFailure(EmpList[i], "Failed");
}
conn.Close();
}
}
}
public static void ValidateBreedingDept(List<Employee> EmpList, string Grp)
{
var connStr = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
string selectQuery;
for (int i = 0; i < EmpList.Count; i++)
{
selectQuery = "Select DepartmentName from Department where Group = #Group AND DepartmentName = #Dept;";
using (MySqlConnection conn = new MySqlConnection(connStr))
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
cmd.Parameters.Add("#Group", MySqlDbType.VarChar).Value = Grp;
cmd.Parameters.Add("#Dept", MySqlDbType.VarChar).Value = EmpList[i].Dept;
conn.Open();
var reader = cmd.ExecuteReader();
List<string> lineList = new List<string>();
while (reader.Read())
{
lineList.Add(reader.GetString(0));
}
if (lineList.Count <= 0)
{
WriteValidationFailure(listOfMouse[i], "Failed");
}
conn.Close();
}
}
}
I am new to connecting to database and querying from c#. And also how to rewrite the queries to use Prepare statements. I understand I can use cmd.Prepare() but can I reuse the parameters from one function in to another.
"reuse my conn and cmd to make more efficiency in the code"
You don't need to worry about that. C# takes care of it by using something called connection pool.
All "closed" connections do not really close the underlying connection but rather returned to the connection pool for later use which is exactly what you are trying to do
Read more on MSDN
Related
I am Creating WinForm application using C# and SqlServer. I have to handle many database CRUD Queries on it. And also there are so many forms and so many controllers.
Now I want to know is, If i create common class for handle database connectivity with many methods for open connection, close connection, execute Sql command or do any other data retrievals. This method is good or bad?
or below method for run every query is good or bad?
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=MYDB"))
{
connection.Open();
// Pool A is created.
}
which method is better for performance and security?
Here are some points to think about when using a connection.
1) Dispose the connection object as soon as you no longer need it by using the using statement:
using (var conn = new SqlConnection(connectionstring))
{
// your sql magic goes here
}
2) If you're not disposing the object immediately, you can make sure the connection is closed using a try-finally statement:
var conn = new SqlConnection(connectionstring);
try
{
// do sql shizzle
}
finally
{
conn.Close();
}
3) To prevent SQL injection, use parameterized queries, never concatenated strings
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using(var comm = new SqlCommand("select * from FooBar where foo = #foo", conn))
{
comm.Parameters.Add(new SqlParameter("#foo", "bar"));
// also possible:
// comm.Parameters.AddWithValue("#foo", "bar");
using(var reader = comm.ExecuteReader())
{
// Do stuff with the reader;
}
}
}
4) If you're performing multiple update, insert or delete statements, and they all need to be succesful at once, use a transaction:
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using(var trans = conn.BeginTransaction())
{
try
{
using(var comm = new SqlCommand("delete from FooBar where fooId = #foo", conn, trans))
{
comm.Parameters.Add(new SqlParameter { ParameterName = "#foo", DbType = System.Data.DbType.Int32 });
for(int i = 0; i < 10 ; i++)
{
comm.Parameters["#foo"].Value = i;
comm.ExecuteNonQuery();
}
}
trans.Commit();
}
catch (Exception exe)
{
trans.Rollback();
// do some logging
}
}
}
5) Stored procedures are used similarly:
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using (var comm = new SqlCommand("FooBarProcedure", conn) { CommandType = CommandType.StoredProcedure })
{
comm.Parameters.Add(new SqlParameter("#FooBar", "shizzle"));
comm.ExecuteNonQuery();
}
}
(Source stored procedures: this Answer)
Multi threading: The safest way to use multi threading and SQL connections is to always close and dispose your connection object. It's the behavior the SqlConnection was designed for. (Source: Answer John Skeet)
Best practice is make a common DBHelper class and create CRUD methods into that class.
I am adding code snippet.This may help you.
web.config
<connectionStrings>
<add name="mssqltips"
connectionString="data source=localhost;initial catalog=mssqltips;Integrated Security=SSPI;"
providerName="System.Data.SqlClient" />
</connectionStrings>
DBHelper.cs
//Opening Connection
public SqlConnection GetConnection(string connectionName)
{
string cnstr = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
SqlConnection cn = new SqlConnection(cnstr);
cn.Open();
return cn;
}
//for select
public DataSet ExecuteQuery(
string connectionName,
string storedProcName,
Dictionary<string, sqlparameter=""> procParameters
)
{
DataSet ds = new DataSet();
using(SqlConnection cn = GetConnection(connectionName))
{
using(SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcName;
// assign parameters passed in to the command
foreach (var procParameter in procParameters)
{
cmd.Parameters.Add(procParameter.Value);
}
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(ds);
}
}
}
return ds;
}
//for insert,update,delete
public int ExecuteCommand(
string connectionName,
string storedProcName,
Dictionary<string, SqlParameter> procParameters
)
{
int rc;
using (SqlConnection cn = GetConnection(connectionName))
{
// create a SQL command to execute the stored procedure
using (SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcName;
// assign parameters passed in to the command
foreach (var procParameter in procParameters)
{
cmd.Parameters.Add(procParameter.Value);
}
rc = cmd.ExecuteNonQuery();
}
}
return rc;
}
If you do not want to dispose context every time you can create repository class and inject SqlConnection inside.
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=MYDB"))
{
repository.SetConnection(connection);
var values = repository.GetSomething();
}
And Create Class:
public Class Repository
{
private SqlConnection _connection {get; set;}
public void SetConnection(SetConnection connection)
{
_connection = connection;
}
public string GetSomething()
{
_connection.Open();
//do stuff with _connection
_connection.Close();
}
}
Anyway I recommend you to read about ORM's (Entity Framework or Dapper) and SQL injection attack.
I am having the below code where I am querying the MySQL database. I need to replace my select query to prepare statement
public static void ValidateName(List<Employees> EmpList, string Grp)
{
var connStr = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
string selectQuery;
for (int i = 0; i < EmpList.Count; i++)
{
selectQuery = "Select EmpName from Employee where group = #Grp AND #Name in (FirstName, LastName);";
using (MySqlConnection conn = new MySqlConnection(connStr))
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
cmd.Parameters.Add("#Grp", MySqlDbType.VarChar).Value = Grp;
cmd.Parameters.Add("#Name", MySqlDbType.VarChar).Value = EmpList[i].Name;
conn.Open();
var reader = cmd.ExecuteReader();
List<string> lineList = new List<string>();
while (reader.Read())
{
lineList.Add(reader.GetString(0));
}
if (lineList.Count <=0)
{
WriteValidationFailure(EmpList[i], "Name doesnot exists in the DB");
}
conn.Close();
}
}
}
This code works perfectly. But for improvement I need to use the prepare statements instead of the query I am using. Because I am having similar kinds of various validation in my code, I am not sure how to reuse the parameters effectively.
You are very close. Just call cmd.Prepare(), keep references to the parameters, and reuse the command:
public static void ValidateName(List<Employees> EmpList, string Grp)
{
var connStr = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
string selectQuery;
selectQuery = "Select EmpName from Employee where group = #Grp AND #Name in (FirstName, LastName);";
using (MySqlConnection conn = new MySqlConnection(connStr)) {
conn.Open();
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
var prmGrp = cmd.Parameters.Add("#Grp", MySqlDbType.VarChar);
var prmName = cmd.Parameters.Add("#Name", MySqlDbType.VarChar);
cmd.Prepare();
for (int i = 0; i < EmpList.Count; i++)
{
prmGrp.Value = Grp;
prmName.Value = EmpList[i].Name;
using (var reader = cmd.ExecuteReader()) {
List<string> lineList = new List<string>();
while (reader.Read())
{
lineList.Add(reader.GetString(0));
}
if (lineList.Count <=0)
{
WriteValidationFailure(EmpList[i], "Name doesnot exists in the DB");
}
}
}
}
conn.Close();
}
}
I'm trying to make a query into the Clients table, when the user enters a mobile number, the code checks if it matches any record, if it does, it returns the client's Name & Address into text boxes, but I'm getting this error "Object reference is not set to an instance of an object" by the time I enter anything into that textbox
here is the code, what could be the problem?
private void textBox11_TextChanged(object sender, EventArgs e)
{
clientsearch();
clientsearch2();
}
public void clientsearch()
{
using (System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data source=|DataDirectory|\\crepeDB.accdb;"))
{
conn.Open();
string query = #"select Cname From Clients where Cmobile = #mobile";
System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(query, conn);
cmd.Parameters.Add("#mobile", System.Data.OleDb.OleDbType.Integer).Value = textBox11.Text;
cmd.ExecuteNonQuery();
string result = cmd.ExecuteScalar().ToString();
textBox12.Text = #result;
}
}
public void clientsearch2()
{
using (System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data source=|DataDirectory|\\crepeDB.accdb;"))
{
conn.Open();
string query = #"select Caddress From Clients where Cmobile = #mobile";
System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(query, conn);
cmd.Parameters.Add("#mobile", System.Data.OleDb.OleDbType.Integer).Value = textBox11.Text;
cmd.ExecuteNonQuery();
string result = cmd.ExecuteScalar().ToString();
textBox13.Text = #result;
}
}
string result = cmd.ExecuteScalar().ToString();
textBox12.Text = #result;
#result isn't anything. You just want result. Additionally, sending separate queries to the server for this data is pointlessly inefficient. Do this instead:
public void clientsearch()
{
string query = #"select Cname, Caddress From Clients where Cmobile LIKE #mobile + '*'";
using (var conn = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data source=|DataDirectory|\\crepeDB.accdb;"))
using (var cmd = System.Data.OleDb.OleDbCommand(query, conn))
{
cmd.Parameters.Add("#mobile", System.Data.OleDb.OleDbType.Integer).Value = textBox11.Text;
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
textBox12.Text = rdr["Cname"].ToString();
textBox13.Text = rdr["Caddress"].ToString();
}
rdr.Close();
}
}
}
Finally, it's better style to also abstract your database code away from user interface. Ideally you would return a Client class, but since I don't see one I'll show an example using a tuple instead:
public Tuple<string, string> FindClientByMobile(string mobile)
{
string query = #"SELECT Cname, Caddress FROM Clients WHERE Cmobile LIKE #mobile + '*'";
using (var conn = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data source=|DataDirectory|\\crepeDB.accdb;"))
using (var cmd = System.Data.OleDb.OleDbCommand(query, conn))
{
cmd.Parameters.Add("#mobile", System.Data.OleDb.OleDbType.Integer).Value = mobile;
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
rdr.Read();
return Tuple<string, string>.Create(rdr["Cname"].ToString(), rdr["Caddress"].ToString());
}
}
}
If you're playing with a Visual Studio 2017 release candidate, you can also use the new Tuple shortcuts:
public (string, string) FindClientByMobile(string mobile)
{
string query = #"SELECT Cname, Caddress FROM Clients WHERE Cmobile LIKE #mobile + '*'";
using (var conn = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data source=|DataDirectory|\\crepeDB.accdb;"))
using (var cmd = System.Data.OleDb.OleDbCommand(query, conn))
{
cmd.Parameters.Add("#mobile", System.Data.OleDb.OleDbType.Integer).Value = mobile;
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
rdr.Read();
return (rdr["Cname"].ToString(), rdr["Caddress"].ToString());
}
}
}
And then use them like this:
private void textBox11_TextChanged(object sender, EventArgs e)
{
var result = FindClientByMobile(textBox11.Text);
textBox12.Text = result.Item1;
textBox13.Text = result.Item2;
}
I am trying to write c# function to read some data from oracle table
My functions:
public static writeConsole(string query, string connectionString, string driver)
{
//driver = Oracle.ManagedDataAccess.Client
using (var conn = DbProviderFactories.GetFactory(driver).CreateConnection())
{
using (var cmd = conn.CreateCommand())
{
cmd.Connection.ConnectionString = connectionString;
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
foreach (var item in ReadDouble(cmd))
{
Console.WriteLine(item);
}
}
}
}
private static IEnumerable<double> ReadDouble(IDbCommand cmd)
{
using (var r = cmd.ExecuteReader())
{
while (r.Read())
yield return r.GetDouble(0);
}
}
There is no problem in connection, nor executing query.
When I read data from oracle table in type number(9) it returns proper values I am expecting.
When I read data from table, where type is number(9,2) it returns empty value (like empty table).
Notice: This is only sample of the code. It has to be written using IDb interfaces
Thank you for help
Possibly it is problem with type mapping. Try this:
http://docs.oracle.com/html/E10927_01/featSafeType.htm#i1008428
And this:
https://community.oracle.com/message/3582080
public static writeConsole(string query, string connectionString, string driver)
{
//driver = Oracle.ManagedDataAccess.Client
using (var conn = DbProviderFactories.GetFactory(driver).CreateConnection())
{
using (var cmd = conn.CreateCommand())
{
cmd.Connection.ConnectionString = connectionString;
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
var reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader[0]+"");
}
}
}
}
You can Try
OracleConnection conn = new OracleConnection(connectionString);
OracleCommand cmd = new OracleCommand(query, conn);
if (conn.State == ConnectionState.Closed)
conn.Open();
OracleDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader[0]+"");
}
If I have a DbCommand defined to execute something like:
SELECT Column1 FROM Table1
What is the best way to generate a List<String> of the returned records?
No Linq etc. as I am using VS2005.
I think this is what you're looking for.
List<String> columnData = new List<String>();
using(SqlConnection connection = new SqlConnection("conn_string"))
{
connection.Open();
string query = "SELECT Column1 FROM Table1";
using(SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
columnData.Add(reader.GetString(0));
}
}
}
}
Not tested, but this should work fine.
Loop through the Items and Add to the Collection. You can use the Add method
List<string>items=new List<string>();
using (var con= new SqlConnection("yourConnectionStringHere")
{
string qry="SELECT Column1 FROM Table1";
var cmd= new SqlCommand(qry, con);
cmd.CommandType = CommandType.Text;
con.Open();
using (SqlDataReader objReader = cmd.ExecuteReader())
{
if (objReader.HasRows)
{
while (objReader.Read())
{
//I would also check for DB.Null here before reading the value.
string item= objReader.GetString(objReader.GetOrdinal("Column1"));
items.Add(item);
}
}
}
}
Or a nested List (okay, the OP was for a single column and this is for multiple columns..):
//Base list is a list of fields, ie a data record
//Enclosing list is then a list of those records, ie the Result set
List<List<String>> ResultSet = new List<List<String>>();
using (SqlConnection connection =
new SqlConnection(connectionString))
{
// Create the Command and Parameter objects.
SqlCommand command = new SqlCommand(qString, connection);
// Create and execute the DataReader..
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
var rec = new List<string>();
for (int i = 0; i <= reader.FieldCount-1; i++) //The mathematical formula for reading the next fields must be <=
{
rec.Add(reader.GetString(i));
}
ResultSet.Add(rec);
}
}
If you would like to query all columns
List<Users> list_users = new List<Users>();
MySqlConnection cn = new MySqlConnection("connection");
MySqlCommand cm = new MySqlCommand("select * from users",cn);
try
{
cn.Open();
MySqlDataReader dr = cm.ExecuteReader();
while (dr.Read())
{
list_users.Add(new Users(dr));
}
}
catch { /* error */ }
finally { cn.Close(); }
The User's constructor would do all the "dr.GetString(i)"
Where the data returned is a string; you could cast to a different data type:
(from DataRow row in dataTable.Rows select row["columnName"].ToString()).ToList();
This version has the same purpose of #Dave Martin but it's cleaner, getting all column, and easy to manipulate the data if you wan't to put it on Email, View, etc.
List<string> ResultSet = new List<string>();
using (SqlConnection connection = DBUtils.GetDBConnection())
{
connection.Open();
string query = "SELECT * FROM DATABASE";
using (SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
var rec = new List<string>();
for (int i = 0; i <= reader.FieldCount - 1; i++)
{
rec.Add(reader.GetString(i));
}
string combined = string.Join("|", rec);
ResultSet.Add(combined);
}
}
}
}