Opening multiple connections with the same database in separate threads simultaneously - c#

While making a software monitoring system in C#, during our testing we encountered a problem with the database connections.
Even if we have declared multiple connections, the programs always throw an exception:
"Current state connection is opening.:"
Why is that?
Is it not possible to have two connections accessing the same database at the same time?
We are using Access Database.
private void UpdateListView(string query)
{
command.Connection = connection;
insertinto = "1";
command.CommandText = "Update ReaderUHF Set Identification = '" + insertinto + "' where EPC = '" + query + "'";
connection.Open();
command.ExecuteNonQuery();
connection.Close();
showdata(insertinto);
}
//After 3 seconds. This thread is performed while the main thread is running
private void FinalLocation()
{
command_1.Connection = connection_1;
finaLoc = "Outside";
command_1.CommandText = "Update ReaderUHF Set Location = '" + insertinto + "' where EPC = '" + query + "'";
connection_1.Open();
command_1.ExecuteNonQuery();
connection_1.Close();
}
It throws an exception of "Current connection state is opening".

You need to only share the connection string between the two threads. Though it has been a long time since I have seen Access used. Can you switch to Sqlite? if it is possible you should do it this way.
It is normally never a good idea to embed SQL code like this into a program but it sounds like this is just a school project so I would change the code to below. Just know in the real world you should do this but should add some Data Access layer like nHibernate or Entity Framework.
private void UpdateLocation(string newLocation, string query, string connectionString)
{
//Using using statements calls close as well as dispose
using(OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
using (OleDbCommand comm = new OleDbCommand())
{
comm.Connection = conn;
comm.CommandText = "Update ReaderUHF Set Location = #location where EPC = #query";
//Always use Parameters to avoid SQL injection
comm.Parameters.AddWithValue("#location", newLocation);
comm.Parameters.AddWithValue("#query", query);
comm.ExecuteNonQuery();
}
}
}
private void UpdateIdentification(string identification, string query, string connectionString)
{
using(OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
using (OleDbCommand comm = new OleDbCommand())
{
comm.Connection = conn;
comm.CommandText = "Update ReaderUHF Set Identification = #identification where EPC = #query";
comm.Parameters.AddWithValue("#identification", identification);
comm.Parameters.AddWithValue("#query", query);
comm.ExecuteNonQuery();
}
}
}
If the above code doesn't work you might have to use a lock to get around multiple connections. Something like this:
private object lockObj = new object();
private void UpdateListView(string query)
{
command.Connection = connection;
insertinto = "1";
command.CommandText = "Update ReaderUHF Set Identification = '" + insertinto + "' where EPC = '" + query + "'";
lock(lockObj)
{
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
showdata(insertinto);
}
//After 3 seconds. This thread is performed while the main thread is running
private void FinalLocation()
{
command_1.Connection = connection_1;
finaLoc = "Outside";
command_1.CommandText = "Update ReaderUHF Set Location = '" + insertinto + "' where EPC = '" + query + "'";
lock(lockObj)
{
connection_1.Open();
command_1.ExecuteNonQuery();
connection_1.Close();
}
}

Whenever a user calls Open on a connection, the pooler looks for an
available connection in the pool. If a pooled connection is available,
it returns it to the caller instead of opening a new connection. When
the application calls Close on the connection, the pooler returns it
to the pooled set of active connections instead of closing it. Once
the connection is returned to the pool, it is ready to be reused on
the next Open call.
http://msdn.microsoft.com/en-us/library/8xx3tyca%28v=vs.110%29.aspx

Related

C# - Mysql select queries not executing

The program I have been creating takes a SQL query as a string parameter and passes it to a method where it is then executed. I am able to open my mysql connection for each query, but for some reason I am unable to run any select statements (I have tried both ExecuteReader and ExecuteScalar).
However, when I run an ExecuteNonQuery, it runs it fine. I am able to verify the insert statement worked from the ExecuteNonQuery.
I currently have the same database up in a SQLyog, using the exact same connection information. While the select statement is running, I am simultaneously running "SHOW FULL PROCESSLIST" and I do not see the query being run. Here is the code I have:
private void buttonConnect_Click(object sender, EventArgs e)
{
string tmp = mysqlSelectScalar("select NAME from PRESIDENTS where name like '%trump%';");
string tmp = mysqlSelectScalar("select COUNT(*) from project.PRESIDENTS;");
mysqlnonQuery("insert into PRESIDENTS (ID,NAME) VALUES ('66','TEST');");
}
public string mysqlSelectScalar(string query)
{
string connString = "server=" + textBoxHostname.Text + ";user=" + textBoxUsername.Text + "; password=" + textBoxPW.Text + ";port=" + textBoxPort.Text + ";database=" + textBoxDB.Text + ";RespectBinaryFlags = false;CharSet=utf8;";
MySqlConnection cnn = new MySqlConnection(connString);
string result = "";
try
{
MessageBox.Show(query);
MySqlCommand cmd = new MySqlCommand(query, cnn);
using (cnn)
{
cnn.Open();
cmd.CommandTimeout = 10;
result = Convert.ToString(cmd.ExecuteScalar());
}
cnn.Close();
}
catch (Exception ex)
{
MessageBox.Show("COULD NOT CONNECT TO DATABASE: " + ex.ToString());
}
return result;
}
public void mysqlnonQuery(string query)
{
string connString = "server=" + textBoxHostname.Text + ";user=" + textBoxUsername.Text + "; password=" + textBoxPW.Text + ";port=" + textBoxPort.Text + ";database=" + textBoxDB.Text + ";RespectBinaryFlags = false;CharSet=utf8;";
MySqlConnection cnn = new MySqlConnection(connString);
string result = "";
try
{
MessageBox.Show(query);
MySqlCommand cmd = new MySqlCommand(query, cnn);
using (cnn)
{
cnn.Open();
cmd.ExecuteNonQuery();
}
cnn.Close();
connStatus = 0;
}
catch (Exception ex)
{
MessageBox.Show("COULD NOT CONNECT TO DATABASE: " + ex.ToString());
connStatus = 1;
}
}
private void outputTable(string query)
{
try
{
string connString = "server=" + textBoxHostname.Text + ";user=" + textBoxUsername.Text + "; password=" + textBoxPW.Text + ";port=" + textBoxPort.Text + ";database=" + textBoxDB.Text + ";RespectBinaryFlags = false;CharSet=utf8;";
MySqlConnection conn = new MySqlConnection(connString);
MySqlCommand cmd = new MySqlCommand(query, conn);
MySqlDataAdapter adpt = new MySqlDataAdapter();
conn.Open();
cmd.CommandTimeout = 5;
MySqlDataAdapter sqladapter = new MySqlDataAdapter(query, conn);
DataSet DS = new DataSet();
sqladapter.Fill(DS);
//the above command is what times out. Everything before runs fine
dataGridViewOutput.DataSource = DS.Tables[0];
MessageBox.Show("dataGridViewOutput.DataSource = DS.Tables[0];");
conn.Clone();
}
catch (Exception ex)
{
richTextBoxOutput.Text = ex.ToString();
}
}
The error message I am getting is from a timeout:
System.TimeoutException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
System.IO.IOException: Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I am sure that the connection string is working because I am able to run the mysqlnonQuery method, and when I put print statements in the mysqlSelectScalar method I saw I was able to get past the opening of the connection.
I should also specify that the table I am selecting from is only 45 records, and I am able to run the same select queries from the mysql command line, which complete in about 0.01 seconds.
This code is also being re-purposed from an older project I was working on, with the exact same mysqlSelectScalar method, and was working perfectly.
Any kind of help would be much appreciated.
using System;
using MySql.Data.MySqlClient;
namespace RetrieveCars
{
class Program
{
static void Main(string[] args)
{
string cs = #"server=localhost;userid=dbuser;password=s$cret;database=testdb";
using var con = new MySqlConnection(cs);
con.Open();
string sql = "SELECT * FROM cars";
using var cmd = new MySqlCommand(sql, con);
using MySqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine("{0} {1} {2}", rdr.GetInt32(0), rdr.GetString(1),
rdr.GetInt32(2));
}
}
}
}

WCF service keeps returning false

So I created and invoked a WCF service in C#, but keep getting a false back, I am unsure as to why it is. It might be to do with the connection string but changing it from the current just gives me errors.
Here's my code:
//Create the new connection
SqlConnection myConnection = new SqlConnection();
//Create the query
String myQuery = "INSERT INTO Player (registrationID, firstName, lastName, phoneNumber, Address, dateOfBirth) " +
" VALUES ('" + registrationID + "', '" + firstName + "', '" + lastName + "', '" + phoneNumber + "', '" + Address + "', '" + dateOfBirth + "');";
//The connectionString can be found in the properties table of the database
myConnection.ConnectionString = "Data Source=C:/Users/User/Documents/Visual Studio 2012/Projects/ADO_LINQ/ADO_LINQ/App_Data/MyDatabase.sdf";
//Initialuze the command
SqlCommand myCommand = new SqlCommand(myQuery, myConnection);
SqlDataReader myReader;
//Run the command
try
{
myConnection.Open();
myReader = myCommand.ExecuteReader();
//Return true if it was successful
return true;
}
catch (Exception ex)
{
return false;
}
As Soner pointed out, your code is susceptible to SQL Injection attacks, and this can be remedied by using parameterized queries. Also, best practice is to use a using block with the connection so it is properly closed and disposed of once the code in the using block is exited (currently you're not even closing the connection when you're done).
Also, ExecuteNonQuery is sufficient for this - it will run the command and then return the number of rows affected (which should be 1 in this case). You can check the number of rows affected and use that to determine success/failure, in addition to using a catch block in the case of an exception. Realistically I would not expect anything other than the value of 1 unless an exception was thrown while executing the command.
Finally your posted code is swallowing the exception. You should do something with the exception (log it, execute some other code, rethrow it - depending on the requirements of your app) rather than simply returning false.
Putting it all together:
using (SqlConnection myConnection = new SqlConnection())
{
// Create the query
String myQuery = "INSERT INTO Player (registrationID, firstName, lastName, phoneNumber, Address, dateOfBirth) " +
" VALUES (#RegistrationID, #FirstName, #LastName, #PhoneNumber, #Address, #DateOfBirth)";
//The connectionString can be found in the properties table of the database
myConnection.ConnectionString = "Data Source=C:/Users/User/Documents/Visual Studio 2012/Projects/ADO_LINQ/ADO_LINQ/App_Data/MyDatabase.sdf";
//Initialuze the command
SqlCommand myCommand = new SqlCommand(myQuery, myConnection);
myCommand.CommandType = CommandType.Text;
// Here you add the values for the parameters in the query
myCommand.Parameters.Add("#RegistrationID", SqlDbType.VarChar).Value = registrationID;
myCommand.Parameters.Add("#FirstName", SqlDbType.VarChar).Value = firstName;
myCommand.Parameters.Add("#LastName", SqlDbType.VarChar).Value = lastName;
myCommand.Parameters.Add("#PhoneNumber", SqlDbType.VarChar).Value = phoneNumber;
myCommand.Parameters.Add("#Address", SqlDbType.VarChar).Value = address;
myCommand.Parameters.Add("#DateOfBirth", SqlDbType.VarChar).Value = dateOfBirth;
//Run the command
try
{
myConnection.Open();
int rowsAffected = myCommand.ExecuteNonQuery();
if (rowsAffected == 1)
{
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
// Do something with the exception, like logging it so you can review the error
return false;
}
}
The above code wraps the call in a using statement. When the command is created, the parameters are added to the SqlCommand.Parameters collection, and then ExecuteNonQuery is returned. If the result is 1, true is returned, otherwise false is returned. If an error is encountered, false is returned but again you should do something with the exception so you can troubleshoot if needed.

error for insert and stored data in access 2013

i have this code for insert data into access 2013
after click in the save button data insert into dataGridView and show
and when stop program and restart this,data not stored in the DB.I've done a lot of searches but can't find the solution. my class code and my button save code
class DB
{
public static OleDbConnection con = new OleDbConnection();
static DB()
{
con.ConnectionString = "Provider=MICROSOFT.ACE.OLEDB.12.0; " +
"Data Source=|DataDirectory|//Phonebook-db.accdb;Persist Security Info=True";
}
public static void Insert(Person p1)
{
try
{
OleDbCommand cmd = con.CreateCommand();
con.Open();
string s = "INSERT INTO Industrialist (S_Name,S_Family,S_Telephone,S_Major)VALUES('" + p1.Name + "','" + p1.Family + "','" + p1.Telephone + "','" + p1.Major + "')";
cmd.CommandType = CommandType.Text;
cmd.CommandText = s;
cmd.ExecuteNonQuery();
con.Close();
System.Windows.Forms.MessageBox.Show("Record successfully Added");
}
catch (OleDbException exp) { MessageBox.Show(exp.ToString()); }
}
}
Person p = new Person();
p.Name = txtname.Text;
p.Family = txtfamily.Text;
p.Telephone = txttell.Text;
p.Major = txtmajor.Text;
DB.Insert(p);
txttell.Text = "";
txtmajor.Text = "";
txtname.Text = "";
txtfamily.Text = "";
List<Person> people = DB.GetPeople();
dataGridView1.DataSource = people;
Choose your ACCDB file listed in your project files, select Copy To Output Directory and set its value to Never (And remember that |DataDirectory| is a substitution strings that points (for ASP.NET projects) to APP_DATA, your record is inserted in the database copied in that directory.
Said that please consider to use a parameterized query to create an sql command, not string concatenations
try
{
OleDbCommand cmd = con.CreateCommand();
con.Open();
string s = "INSERT INTO Industrialist (S_Name,S_Family,S_Telephone,S_Major)VALUES(" +
"?,?,?,?)";
cmd.CommandText = s;
cmd.Parameters.AddWithValue("#p1",p.Name);
cmd.Parameters.AddWithValue("#p2",p.Family);
cmd.Parameters.AddWithValue("#p3",p.Telephone);
cmd.Parameters.AddWithValue("#p4",p.Major);
cmd.ExecuteNonQuery();
con.Close();
System.Windows.Forms.MessageBox.Show("Record successfully Added");
}
catch (OleDbException exp) { MessageBox.Show(exp.ToString()); }
Of course do not close the connection before executing the command.
Another point to change is the usage pattern of your connection. Do not create a global connection and keep it around for the lifetime of your application. Simply create and use it when needed and close/dispose immediately after
using(OleDbConnection con = new OleDbConnection("Provider=MICROSOFT.ACE.OLEDB.12.0; " +
"Data Source=|DataDirectory|//Phonebook-db.accdb;" +
"Persist Security Info=True"))
{
try
{
OleDbCommand cmd = con.CreateCommand();
....
}
} // <- Here at the closing brace the connectio will be close and disposed

Trouble with query, execute non scalar not behaving as I thought

I'm having trouble with a SQL query:
using (SqlConnection conn = new SqlConnection("user id=user;" + "password=pass;" + "server=server;" + "database=db;"))
{
using (SqlCommand comm = new SqlCommand(#"SELECT COUNT(*) FROM [CompaniesDB].[dbo].[Companies] WHERE BolagsID = '" + BolagsID + "'"))
{
conn.Open();
comm.Connection = conn;
MessageBox.Show("TEST: {0}", Convert.ToString((int)comm.ExecuteScalar()));
}
}
I'm expecting to get an int in the message box conveying the number of rows that BolagsID occurs in. But I get 0 every time. I've tried the query in SQL Server Management Studio and it works fine there. What am I doing wrong/missing?
EDIT:
This works, but now I don't know how to parameterize the values:
string query = #"SELECT COUNT(*) FROM [CompaniesDB].[dbo].[Companies] WHERE BolagsID = " + BolagsID;
ADODB.Connection conn2 = new ADODB.Connection();
ADODB.Recordset rs = new ADODB.Recordset();
string strConn = "Provider=...;Data Source=...;Database=...;User Id=...;Password=...";
conn2.Open(strConn);
rs.CursorType = ADODB.CursorTypeEnum.adOpenStatic;
rs.Open(query, conn2);
if (rs.Fields[0].Value > 0)
...stuff...
Like others are saying, parameters are a good idea. Here's something to get you started:
string query = #"SELECT Count(*) FROM [CompaniesDB].[dbo].[Companies] WHERE BolagsID = #BolagsID";
using (SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add("#BolagsID", SqlDbType.NVarChar).Value = BolagsID;
conn.Open();
MessageBox.Show("TEST: {0}", Convert.ToString((int)cmd.ExecuteScalar()));
conn.Close();
}
Basically a 0 is returned if there is an error in your query, so even though SSMS is smart enough to resolve it, the sql command isn't.
A quick way to make sure that everything else is working okay is to change the query to just "SELECT Count(*) FROM [CompaniesDB].[dbo].[Companies]". If that doesn't work then the issue could lie with your database connection (permissions?) or something else.
Try assigning SELECT COUNT(*) FROM [CompaniesDB].[dbo].[Companies] WHERE BolagsID = '" + BolagsID + "'" to a string str as follows
string str =#"SELECT COUNT(*) FROM [CompaniesDB].[dbo].[Companies] WHERE BolagsID = '" + BolagsID + "'";
using (SqlConnection conn = new SqlConnection("user id=user;" + "password=pass;" + "server=server;" + "database=db;"))
{
using (SqlCommand comm = new SqlCommand(str))
{
conn.Open();
comm.Connection = conn;
MessageBox.Show("TEST: {0}", Convert.ToString((int)comm.ExecuteScalar()));
}
}
Then do a watch/quickwatch on str's value to get the exact query that is getting run and then run the same query in Sql Managment studio. If you get 0 in Sql Management Studio as well, then the problem is that the data is just not there.
I tried a lot of stuff before trying out a whole different approach. This gives me the result I want:
string query = #"SELECT COUNT(*) FROM [CompaniesDB].[dbo].[Companies] WHERE BolagsID = " + BolagsID;
ADODB.Connection conn2 = new ADODB.Connection();
ADODB.Recordset rs = new ADODB.Recordset();
string strConn = "Provider=...;Data Source=...;Database=...;User Id=...;Password=...";
conn2.Open(strConn);
rs.CursorType = ADODB.CursorTypeEnum.adOpenStatic;
rs.Open(query, conn2);
if (rs.Fields[0].Value > 0)
...stuff...
Note that both connection and record set are closed outside of this code snippet.

Problem with multiple SqlDataReader and SqlCommand in a Class

I have a problem with C#, I have a Class with a function for SqlDataReader and another for SqlCommand (the first one is just for read values from a DataBase and the second one is for INSERT, UPDATE, DELETE ... in the same DB).
The problem is, for the first part of the code (the login), I have to search the values from an Active Directory (it works), then I must see if the user has username and password in my own DB (it works), and then, if the user is not in the DB then I have to create it and get the ID, if it is already created then I just have to get the ID.
The problem is that I get this message :
InvalidOperationException was
unhandled by user code
There already exist an Open DataReader
associated with this Command, who as
to be closed first.
There is the code :
Class.cs :
private static string MyConnectionString = "THIS IS MY CONNECTION";
private SqlConnection MyConnection = new SqlConnection(MyConnectionString);
public SqlCommand MyCommand = new SqlCommand();
public SqlDataReader MyReader = null;
public void DBMyReader(String SqlQuery)
{
if (MyConnection.State != ConnectionState.Open)
MyConnection.Open();
MyCommand.Connection = MyConnection;
MyCommand.CommandText = SqlQuery;
MyReader = MyCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
public void DBMyUpdate(String SqlQuery)
{
if (MyConnection.State != ConnectionState.Open)
MyConnection.Open();
var cmdTest = new SqlCommand();
cmdTest.Connection = MyConnection;
cmdTest.CommandText = SqlQuery;
cmdTest.ExecuteNonQuery();
}
public void DBMyInsert(String SqlQuery)
{
DBMyUpdate(SqlQuery);
}
** Login.aspx.cs: **
MyClass.DBMyReader("SELECT util_codi,util_logi,util_nome FROM Tgep_util WHERE util_logi='"
+ Session["username"].ToString() + "'");
MyClass.MyReader.Read();
if (!MyClass.MyReader.HasRows)
{
MyClass.MyReader.Close();
MyClass.DBMyInsert("INSERT INTO Tgep_util(util_logi,util_nome) "
+ "VALUES ('" + Session["username"].ToString() + "','" + Session["nome"].ToString() + "')");
}
MyClass.DBMyReader("SELECT util_codi,util_logi,util_nome FROM Tgep_util WHERE util_logi='"
+ Session["username"].ToString() + "'");
MyClass.MyReader.Read();
Session["user_id"] = MyClass.MyReader["util_codi"].ToString();
Response.Redirect("FRM_Principal.aspx");
Edit : Update Code (Works for now)
The error means exactly what it says.. You have loaded a SQLCommand and started reading rows, and are now trying to do an insert. You need to close out that reader first, or use a new command.
in the DBMyUpdate function you could just create a new command:
public void DBMyUpdate(String SqlQuery)
{
if (MyConnection.State != ConnectionState.Open)
MyConnection.Open();
var cmdUpdate = new SqlCommand();
cmdUpdate.Connection = MyConnection;
cmdUpdate.CommandText = SqlQuery;
cmdUpdate.ExecuteNonQuery(CommandBehavior.CloseConnection);
}
edit: based on comments to this answer, it required using separate connections which seems odd/incorrect.
You can't use the same DataReader for insert/update that you used for insertion. You have to close the DataReader first before associating some other command with the DataReader.

Categories

Resources