Multi users safe SQL Connection - c#

I have an object below:
public class DatabaseAccess
{
private static string sConnStr;
private static SqlConnection sqlConn;
private static string ConnectionString
{
get
{
if (String.IsNullOrEmpty(sConnStr))
{
sConnStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
}
return sConnStr;
}
}
public static int OpenConnection
{
get
{
sqlConn = new SqlConnection(ConnectionString);
return 0;
}
}
public static SqlConnection Connection
{
get
{
if (sqlConn.State != ConnectionState.Open)
{
sqlConn = new SqlConnection(ConnectionString);
sqlConn.Open();
}
return sqlConn;
}
}
}
So whenever I need a connection in my web application, I use something like:
DataTable dt = new DataTable();
using (SqlConnection cnn = DatabaseAccess.Connection)
{
using (SqlDataAdapter da = new SqlDataAdapter("MyAStoredProcedure", cnn))
{
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.Fill(dt);
}
}
return dt;
It all seems well except when there are 2 users running the codes at the same time, I will get in my web application the following error:
There is already an open DataReader associated with this Command needs to be Closed.
I need some advice how do I resolve the above issue?
Thank you.

That's because you're sharing connection objects - don't do that. DatabaseAccess.Connection should create a new SqlConnection every time.

Try to create a new instance of SqlConnection in the using statement
DataTable dt = new DataTable();
using (SqlConnection cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
{
cnn.Open();
using (SqlDataAdapter da = new SqlDataAdapter("MyAStoredProcedure", cnn))
{
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.Fill(dt);
}
}
return dt;

Related

Set datatables to be equivalent

This is probably a simple question but I am not experienced in C#.
I have 2 datatables, 1 is basically a copy of the other (like a table to review information). To set the values this is what I am doing now:
string attribute1 = "";
string attribute2 = "";
string attribute3 = "";
.....
DataTable result = new DataTable();
using (SqlConnection con = new SqlConnection("user id=user_id;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand("SELECT * FROM table1 WHERE parameter=#identifying_parameter", con))
{
cmd.Parameters.AddWithValue("#identifying_parameter", "example");
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
attribute1 = Convert.ToString(reader["attribute1"]);
attribute2 = Convert.ToString(reader["attribute2"]);
attribute3 = Convert.ToString(reader["attribute3"]);
.....
}
con.Close();
}
}
using (SqlConnection con = new SqlConnection("user id=user_2;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand("INSERT INTO table2 (attribute1, attribute2, attribute3, ...) VALUES(#attribute1, #attribute2, #attribute3, ...)", con))
{
cmd.Parameters.AddWithValue("#attribute1", attribute1);
cmd.Parameters.AddWithValue("#attribute2", attribute2);
cmd.Parameters.AddWithValue("#attribute3", attribute3);
....
con.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(result);
con.Close();
da.Dispose();
}
}
Obviously I might have a lot of attributes, so is there a simpler way to set every attribute in the table to be equal in C#?
You can use INSERT..INTO..SELECT
DataTable result = new DataTable();
using (SqlConnection con = new SqlConnection("user id=user_2;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand(#"INSERT INTO table2 (attribute1, attribute2, attribute3, ...)
SELECT attribute1, attribute2, attribute3 ... FROM table1
WHERE parameter=#identifying_parameter
", con))
{
cmd.Parameters.AddWithValue("#identifying_parameter", "example");
con.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(result);
con.Close();
da.Dispose();
}
}
You can use * instead of specifying the column name, although which is not good practice..
In order to make a second Table identical (or "equivalent" as per your definition) to the first one (for certainty let's call it sourceTable), you can use SqlBulkCopy.WriteToServer Method (DataTable)(re: https://msdn.microsoft.com/en-us/library/ex21zs8x%28v=vs.110%29.aspx)
using (SqlConnection YourConnection= new SqlConnection(YourConnectionString))
{
YourConnection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(YourConnection))
{
bulkCopy.DestinationTableName = "dbo.YourDestinationTable";
try
{
// Write from the source to the destination.
bulkCopy.WriteToServer(sourceTable);
}
catch (Exception ex) { }
}
}
In order to get a sourceTable you can use the following code snippet:
DataTable sourceTable = SqlReadDB(YourConnString, "SELECT *")
private static DataTable SqlReadDB(string ConnString, string SQL)
{
DataTable _dt;
try
{
using (SqlConnection _connSql = new SqlConnection(ConnString))
{
using (SqlCommand _commandl = new SqlCommand(SQL, _connSql))
{
_commandSql.CommandType = CommandType.Text;
_connSql.Open();
using (SqlCeDataReader _dataReaderSql = _commandSql.ExecuteReader(CommandBehavior.CloseConnection))
{
_dt = new DataTable();
_dt.Load(_dataReaderSqlCe);
_dataReaderSql.Close();
}
}
_connSqlCe.Close();
return _dt;
}
}
catch { return null; }
}
}
Hope this may help.

Connecting to MS Access from C#

I found this code online, which connects from C# to an SQL server database.
I wish to do something similar, but I want to connect to an Access 2010 database.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace WindowsFormsApplication1.DAL
{
public class PersonDAL
{
public string ConString =
"Data Source=SOURAV-PC\\SQL_INSTANCE;Initial Catalog=test;Integrated Security=True";
SqlConnection con = new SqlConnection();
DataTable dt = new DataTable();
public DataTable Read()
{
con.ConnectionString = ConString;
if (ConnectionState.Closed == con.State)
con.Open();
SqlCommand cmd = new SqlCommand("select * from Person",con);
try
{
SqlDataReader rd = cmd.ExecuteReader();
dt.Load(rd);
return dt;
}
catch
{
throw;
}
}
public DataTable Read(Int16 Id)
{
con.ConnectionString = ConString;
if (ConnectionState.Closed == con.State)
con.Open();
SqlCommand cmd = new SqlCommand("select * from Person where ID= "+ Id +"", con);
try
{
SqlDataReader rd = cmd.ExecuteReader();
dt.Load(rd);
return dt;
}
catch
{
throw;
}
}
}
}
How should I change my code to do that ?
For the example, let's assume that my access DB is in: C:\VisualStudioProject\Sample
Thank you!
You need to do the following:
Use Connection string as:
string connectionstring = Standard security
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccessFile.accdb;
Persist Security Info=False;
Use OLEDB instead of SQL
OleDbConnection MyConn = new OleDbConnection(connectionstring);
public class PersonDAL
{
public string ConString =
#"Standard security Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccessFile.accdb; Persist Security Info=False;";
OleDbConnection con;
DataTable dt;
public PersonDAL()
{
con = new OleDbConnection();
dt = new DataTable();
}
public DataTable Read()
{
con.ConnectionString = ConString;
if (ConnectionState.Closed == con.State)
con.Open();
OleDbCommand cmd = new OleDbCommand("select * from Person", con);
try
{
OleDbDataReader rd = cmd.ExecuteReader();
dt.Load(rd);
return dt;
}
catch
{
throw;
}
}
public DataTable Read(Int16 Id)
{
con.ConnectionString = ConString;
if (ConnectionState.Closed == con.State)
con.Open();
OleDbCommand cmd = new OleDbCommand("select * from Person where ID= " + Id + "", con);
try
{
OleDbDataReader rd = cmd.ExecuteReader();
dt.Load(rd);
return dt;
}
catch
{
throw;
}
}
}

Fill: SelectCommand.Connection property has not been initialized

I am using the below code to access the MS Access Database. But i got a error message Fill: SelectCommand.Connection property has not been initialized.How can i solve this issue.
common.cs
=========
public static bool DBConnectionStatus()
{
try
{
string conString = #"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=|DataDirectory|db_admin.mdb; Jet OLEDB:Database Password=admin";
using (OleDbConnection conn = new OleDbConnection(conString))
{
conn.Open();
return (conn.State == ConnectionState.Open);
}
}
catch (OleDbException)
{
return false;
}
protected void btn_general_Click(object sender, EventArgs e)
{
try
{
bool state = common.DBConnectionStatus();
if (state == true)
{
cmd = new OleDbCommand("select * from tbl_admin");
da = new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds); // Error Here
if (ds.Tables[0].Rows.Count > 0)
{
}
}
}
catch (Exception e1)
{
}
}
I did suggest you to modify your code to something like this:
private DataTable YourData()
{
string conString = #"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=|DataDirectory|db_admin.mdb; Jet OLEDB:Database Password=admin";
DataSet ds = new DataSet();
using (SqlConnection conn = new SqlConnection(conString))
{
try
{
conn.Open();
SqlCommand command = new SqlCommand("select * from tbl_admin", conn);
command.CommandType = CommandType.Text;
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
// do somethign here
}
}
catch (Exception)
{
/*Handle error*/
}
}
return ds.Tables[0];
}
And then:
protected void btn_general_Click(object sender, EventArgs e)
{
this.YourData(); // you will get the Data here. you can then use it the way you want it
}
You are initializing a Command which you use to construct a DataAdapter, but both without setting the required Connection property:
cmd = new OleDbCommand("select * from tbl_admin"); // <-- no connectuion assigned
da = new OleDbDataAdapter(cmd); // <-- no connectuion assigned
So your exception is pretty self-explanatory.
One final note: using will dispose/close the connection, so the method DBConnectionStatus is pointless. So don't use it, instead use the using in in the first place:
try
{
using(var con = new OleDbConnection(connectionString))
using(var da = new OleDbDataAdapter("elect * from tbl_admin", con))
{
var table = new DataTable();
da.Fill(table); // note that you don't need to open the connection with DataAdapter.Fill
if (table.Rows.Count > 0)
{
// ...
}
}
}
catch (Exception e1)
{
// don't catch an exception if you don't handle it in a useful way(at least loggging)
throw;
}
As per your requirement you can also use SqlDataAdapter instand of ExecuteReader.
public void ReadMyData(string connectionString)
{
string queryString = "SELECT OrderID, CustomerID FROM Orders";
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
OleDbCommand command = new OleDbCommand(queryString, connection);
connection.Open();
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1));
}
// always call Close when done reading.
reader.Close();
}
}

MySQL Connection will not close

This is really simple, all i'm trying to do is fill a datatable, i have everything surrounded by using() and the connection will not dispose/close. Please help
DataTable loginTbl = MySQLProcessing.MySQLProcessor.StoreProcedureDTTable("Login", ParamArgs, "Login");
public static DataTable StoreProcedureDTTable(string mysqlQuery, List<string> CommandArgs, string queryName)
{
DataTable DTTableTable = new DataTable();
using (MySqlCommand MySQLCommandFunc = new MySqlCommand(mysqlQuery))
{
MySQLCommandFunc.CommandType = CommandType.StoredProcedure;
foreach (string args in CommandArgs)
{
string[] splitArgs = args.Split('|');
MySQLCommandFunc.Parameters.AddWithValue(splitArgs[0], splitArgs[1]);
}
using (MySqlDataAdapter DataDTTables = new MySqlDataAdapter(MySQLCommandFunc))
{
DataDTTables.SelectCommand.CommandTimeout = 240000;
lock (_object)
{
using (MySqlConnection con = new MySqlConnection(ConfigurationManager.ConnectionStrings["mysqlCon"].ConnectionString))
{
MySQLCommandFunc.Connection = con;
DataDTTables.Fill(DTTableTable);
}
}
}
}
DataTable catchConnectionTable = DTTableTable;
DTTableTable.Dispose();
return catchConnectionTable;
}
Add Pooling=False to the connection string
Have you tried:
using (MySqlConnection con = new MySqlConnection(ConfigurationManager.ConnectionStrings["mysqlCon"].ConnectionString))
{
con.open();
MySqlDataAdapter DataDTTables = new MySqlDataAdapter(MySQLCommandFunc)
DataDTTables.SelectCommand.CommandTimeout = 240000;
MySQLCommandFunc.Connection = con;
DataDTTables.Fill(DTTableTable);
con.close();
}
?
Alternatives to Pooling=false are SqlConnection.ClearPool and SqlConnection.ClearAllPools methods. For more information read: SQL Server Connection Pooling (ADO.NET)

Question about showing sql server data in a tabbed view

I am creating a inventory app using c# that pulls its info from sql server. I am making it a tabbed view, with each tab representing a different type of item. I have included some of my code, what I am trying to figure is, is there a better way to do this? I dont feel like the way I am doing is right, even though it works. All my queries for each tab are stored procedures. Secondly, How would I insert and update the database through the grid?
public partial class InventoryWindow : Window
{
private InventoryDS InvDS;
private String connString = "server=PC-server;database=Inventory;user=user;password=password";
String sqlString_Routers = InventoryOutputQuery.InventorySummary_Routers();
public InventoryWindow()
{
InitializeComponent();
if (dgDataView != null)
{
SqlConnection con = new SqlConnection(connString);
SqlDataAdapter adpt = new SqlDataAdapter(sqlString_Routers, con);
DataSet ds = new DataSet();
adpt.Fill(ds, sqlString_Routers);
dgDataView.DataContext = ds;
}
}
private void showTaps()
{
String sqlString_Taps = InventoryOutputQuery.InventorySummary_Routers();
SqlConnection con = new SqlConnection(connString);
con.Open();
SqlCommand cmd = new SqlCommand(sqlString_Routers, con);
SqlDataReader dr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
dgDataView.DataContext = dt;
con.Close();
}
private void showPower()
{
String sqlString_Power = InventoryOutputQuery.InventorySummary_Power();
SqlConnection con = new SqlConnection(connString);
con.Open();
SqlCommand cmd = new SqlCommand(sqlString_Power, con);
SqlDataReader dr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
dgDataView.DataContext = dt;
con.Close();
}
private void showSwitches()
{
String sqlString_Switches = InventoryOutputQuery.InventorySummary_Switches();
SqlConnection con = new SqlConnection(connString);
con.Open();
SqlCommand cmd = new SqlCommand(sqlString_Switches, con);
SqlDataReader dr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
dgDataView.DataContext = dt;
con.Close();
}
And below is how i bind it to the grid:
public void BindGrid(string view)
{
switch (view.ToUpper())
{
case "Routers":
showTaps();
break;
case "POWER":
showPower();
break;
case "SWITCHES":
showSwitches();
break;
case "HUBS":
showHubs();
private void tcDataView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
TabItem ti = tcDataView.SelectedItem as TabItem;
if (ti != null)
BindGrid(ti.Header.ToString());
}
break;
My suggestion is to be careful with how we handle SqlConnection. It is a scarce resource and it will run out pretty soon if we are not careful.
Please wrap sql code in a using block, for example:
using (SqlConnection con = new SqlConnection(connString))
{
SqlDataAdapter adpt = new SqlDataAdapter(sqlString_Routers, con);
DataSet ds = new DataSet();
adpt.Fill(ds, sqlString_Routers);
dgDataView.DataContext = ds;
}
The following link will explain the effect of 'using' block in a bit more details.
http://www.codeproject.com/KB/cs/tinguusingstatement.aspx

Categories

Resources