Why is the 2nd Command inside a Connection does not work? - c#

I'm trying to do a test in two tables based on what the user entered in the login TextBox, So I test the LoginName if it is in Table "Redacteur"; else I make a new Command that will look inside another table "Membres".
Problem is: the command works when I enter a loginName that is in the table "Redacteur", but Once I enter a loginName that belongs to the Membres's table It doesn't redirect me to the page I'm requesting inside the code. I think it doesn't even enter the Else section.
using(SqlConnection connect = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand("select * from Redacteurs where RedCode= #lg", connect);
cmd.Parameters.AddWithValue("#lg", TextLogIn.Text);
connect.Open();
//cmd.ExecuteNonQuery();
SqlDataReader rd = cmd.ExecuteReader();
if (rd.HasRows)
{
rd.Read();
Session["code"] = rd["RedCode"].ToString();
Session["loginname"] = TextLogIn.Text;
Session["pass"] = TextPass.Value;
Response.Redirect("RedacteurPage.aspx?Redact="
+ Session["loginname"].ToString());
rd.Close();
}
else
{
cmd = new SqlCommand("select * from Membres where LoginMembre = #lm", connect);
cmd.Parameters.AddWithValue("#lm", TextLogIn.Text);
//cmd.ExecuteNonQuery();
SqlDataReader rd2 = cmd.ExecuteReader();
if (rd2.HasRows)
{
rd2.Read();
Session["code"] = rd2["MembreCode"].ToString();
Session["loginname"] = TextLogIn.Text;
Session["pass"] = TextPass.Value;
Response.Redirect("ProductCatalogue.aspx?user=" + rd2["FullName"]);
rd2.Close();
}
}
}

You need to close/dispose the first command before you can execute one on the same connection.
The quick-and-dirty (i.e. works but not recommended) solution would be to have rd.Close() in the first line of your else block.

Related

"There is already an open DataReader associated with this Command which must be closed first."

I'm working on application which needs to connect to another database to get some data,
and to do that, I decided to use SqlConnection, reader etc..
And I need to execute few queries, for example first I need to get CARD ID for some user, after that I need to get some data by that CARD ID..
Here is my code:
#region Connection to another Database
SqlConnection sqlConnection1 = new SqlConnection("Data Source=ComputerOne; Initial Catalog=TestDatabase;Integrated Security=False; User ID=test; Password=test123;");
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
cmd.CommandText = "Select * From Users Where CardID=" + "'" + user.CardID + "'";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
reader = cmd.ExecuteReader();
string cardID = "";
string quantity="";
while (reader.Read())
{
cardID = reader["CardID"].ToString();
}
//HOW COULD I WRITE ANOTHER QUERY NOW, FOR EXAMPLE, OK I GOT CARDID NOW GIVE ME SOME OTHER THINGS FROM THAT DATABASE BY THAT cardID
//here I tried to change CommandText and to keep working with reader.. but its not working like this because its throwing me exception mention in question title.
cmd.CommandText = "Select T1.CardID, T2.Title, Sum(T1.Quantity) as Quantity From CardTransactions as T1 JOIN Adds as T2 ON T1.AddsID = T2.AddsID Where T1.CardID =" + cardID + "AND T1.Type = 1 Group By T1.CardID, T2.Title";
reader = cmd.ExecuteReader();
while (reader.Read())
{
quantity = reader["Quantity"].ToString();
}
// Data is accessible through the DataReader object here.
sqlConnection1.Close();
#endregion
So guys how could I execute few queries statemens using this example.
Thanks a lot!
Cheers
Your problem is that you are not disposing the objects you are using. For that purpose is better to always use using structure, since it will guarantee you that everithing is gonna be disposed. Try the code below:
SqlConnection sqlConnection1 = new SqlConnection("Data Source=ComputerOne; Initial Catalog=TestDatabase;Integrated Security=False; User ID=test; Password=test123;");
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
string cardID = "";
string quantity="";
using(sqlConnection1 = new SqlConnection("Data Source=ComputerOne; Initial Catalog=TestDatabase;Integrated Security=False; User ID=test; Password=test123;"))
{
sqlConnection1.Open();
using(cmd = new SqlCommand())
{
cmd.CommandText = "Select * From Users Where CardID=" + "'" + user.CardID + "'";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection1;
using(reader = cmd.ExecuteReader())
{
while (reader.Read())
{
cardID = reader["CardID"].ToString();
}
} //reader gets disposed right here
} //cmd gets disposed right here
using(cmd = new SqlCommand())
{
cmd.CommandText = "Select T1.CardID, T2.Title, Sum(T1.Quantity) as Quantity From CardTransactions as T1 JOIN Adds as T2 ON T1.AddsID = T2.AddsID Where T1.CardID =" + cardID + "AND T1.Type = 1 Group By T1.CardID, T2.Title";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection1;
using(reader = cmd.ExecuteReader())
{
while (reader.Read())
{
quantity = reader["Quantity"].ToString();
}
} //reader gets disposed right here
} //cmd gets disposed right here
sqlConnection1.Close();
} //sqlConnection1 gets disposed right here
The reader you opened is still active and open. And you can have just one active reader at a time. You should wrap all Sql... instances in a using to ensure they get closed properly.
using (SqlConnection connection = new SqlConnection(...))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
// the code using reader
}
}
well ... you receive the error because the used reader for the first call was not closed. You should always call the Close method when you have finished using the DataReader object insuring that the connection used by the reader is returned to the connection pool (the connection is in use exclusively by that DataReader). Partial code:
reader = cmd.ExecuteReader();
try
{
while(myReader.Read())
{
while (reader.Read())
{
cardID = reader["CardID"].ToString();
}
}
finally
{
myReader.Close();
}
...
reader = cmd.ExecuteReader();
try
{
while(myReader.Read())
{
reader = cmd.ExecuteReader();
while (reader.Read())
{
quantity = reader["Quantity"].ToString();
}
}
}
finally
{
myReader.Close();
myConnection.Close();
}
Also... as a clean code rule, separate your calls in different methods (SOLID principles)

C# SQL wrong INNER JOIN data is being displayed don't know why

The problem I have is I've made a program where user may log in to check their account information (login with username and password from SQL database) however if I log in with details A then log out and Log in with details B. it will still display account information of User A but with User B log in details.
public string Username { get; set; }
//gets Username from Login form (another form)//
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=E:\Graded unit Dev\BlackMarch\BlackMarch\bin\Debug\DataBaseBM.mdf;Integrated Security=True;Connect Timeout=30");
/* (2) */
SqlCommand cmd = new SqlCommand(#"SELECT *
FROM UserData
INNER JOIN HotelData
ON (UserData.Username = HotelData.Username) ", con);
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
txtboxPass.Text = dr["password"].ToString();
txtboxFN.Text = dr["FirstName"].ToString();
txtboxSurname.Text = dr["Surname"].ToString();
txtboxAge.Text = dr["Age"].ToString();
txtboxGender.Text = dr["Gender"].ToString();
txtboxMobile.Text = dr["Mobile"].ToString();
txtboxEmail.Text = dr["Email"].ToString();
txtboxRoomType.Text = dr["RoomType"].ToString();
txtboxNoRooms.Text = dr["NoOfRooms"].ToString();
txtboxPackage.Text = dr["PackageDeal"].ToString();
txtboxGym.Text = dr["Gym"].ToString();
txtboxBeach.Text = dr["Beach"].ToString();
txtboxPool.Text = dr["SwimmingPool"].ToString();
txtboxSports.Text = dr["SportsGround"].ToString();
txtDate.Text = dr["StartDateR"].ToString();
strNoNights = dr["NoOfNights"].ToString();
strNoDays = dr["NoOfDays"].ToString();
You aren't specifying the username in your query. A join will just return all the records for all users. If you want to get data for a specific user you need to use a parameterized query that passes in the name of the current user.
This query has no WHERE condition so your code gets all data produced by the JOIN but because your while loop replaces all the data from the previous loop with the current one you end up with your controls always showing the data of the last user read
To fix you need to add a WHERE condition to your sql text in such a way that only the data of the current logged in user will be retrieved. From your code I don't know how do you store the username of the logged in user so let's assume that is stored in a variable named UserName
string cmdText = #"SELECT *
FROM UserData
INNER JOIN HotelData
ON (UserData.Username = HotelData.Username)
WHERE UserData.UserName = #user";
using(SqlConnection con = new SqlConnection(#"....."))
using(SqlCommand cmd = new SqlCommand(cmdText, con);
{
con.Open();
cmd.Parameters.Add("#user", SqlDbType.NVarChar).Value = UserName;
using(SqlDataReader dr = cmd.ExecuteReader())
{
// Now this will loop just one time, only for the logged in user
while (dr.Read())
{
....
}
}
}

how two get data from 2 different table c#

I have two table.I need to get calorificValue from the food table and daily_gained from the calorie_tracker table to then make some calculations.I've written this code, I know it not efficent. It retrieves daily_gained but failed to get calorificValue.
MySqlCommand cmd = new MySqlCommand("SELECT name,calorificValue FROM myfitsecret.food where name=#name", cnn);
MySqlCommand cmd2 = new MySqlCommand("SELECT sportsman_id,daily_gained FROM myfitsecret.calorie_tracker where sportsman_id=#sportsman_id", cnn);
cmd2.Parameters.AddWithValue("#sportsman_id", Login.userID);
string s = (comboBox1.SelectedItem).ToString();
cmd.Parameters.AddWithValue("#name",s);
cmd2.Connection.Open();
MySqlDataReader rd = cmd2.ExecuteReader(CommandBehavior.CloseConnection);
int burned = 0;
if (rd.HasRows) // if entered username and password have the data
{
while (rd.Read()) // while the reader can read
{
if (rd["sportsman_id"].ToString() == Login.userID) // True for admin
{
burned += int.Parse(rd["daily_gained"].ToString());
}
}
}
cmd2.Connection.Close();
cmd.Connection.Open();
MySqlDataReader rd2 = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (rd2.HasRows) // if entered username and password have data
{
while (rd2.Read()) // while the reader can read
{
if (rd2["name"].ToString() == s)
{
burned += int.Parse(rd2["calorificValue"].ToString());
}
}
}
MessageBox.Show(burned+"");
DataTable tablo = new DataTable();
string showTable = "SELECT * from myfitsecret.calorie_tracker where sportsman_id=#sportsman_id";
MySqlDataAdapter adapter = new MySqlDataAdapter();
MySqlCommand showCommand = new MySqlCommand();
showCommand.Connection = cnn;
showCommand.CommandText = showTable;
showCommand.CommandType = CommandType.Text;
showCommand.Parameters.AddWithValue("#sportsman_id", Login.userID);
adapter.SelectCommand = showCommand;
adapter.Fill(tablo);
dataGridView1.DataSource = tablo;
cnn.Close();
Why don't you just use the scalar function SUM and let the database do its job instead of writing a lot of code?
int burned = 0;
string s = comboBox1.SelectedItem.ToString();
cnn.Open();
string cmdText = #"SELECT SUM(calorificValue)
FROM myfitsecret.food
WHERE name=#name";
using(MySqlCommand cmd = new MySqlCommand(cmdText, cnn))
{
cmd.Parameters.Add("#name", MySqlDbType.VarChar).Value = s;
object result = cmd.ExecuteScalar();
burned += (result != null ? Convert.ToInt32(result) : 0);
}
cmdText = #"SELECT SUM(daily_gained)
FROM myfitsecret.calorie_tracker
WHERE sportsman_id=#sportsman_id";
using(MySqlCommand cmd = new MySqlCommand(cmdText, cnn))
{
cmd.Parameters.Add("#sportsman_id", MySqlDbType.Int32).Value = Login.userID;
object result = cmd.ExecuteScalar();
burned += (result != null ? Convert.ToInt32(result) : 0);
}
Not visible from your code, but also the connection should be created inside a using statement (very important with MySql that is very restrictive with simultaneous open connections)
We could also use a different approach putting the two commands together and separating them with a semicolon. This is called batch commands and they are both executed with just one trip to the database. Of course we need to fallback using the MySqlDataReader to get the two results passing from the first one to the second one using the NextResult() method (see here MSDN for Sql Server)
string cmdText = #"SELECT SUM(calorificValue)
FROM myfitsecret.food
WHERE name=#name;
SELECT SUM(daily_gained)
FROM myfitsecret.calorie_tracker
WHERE sportsman_id=#sportsman_id";
using(MySqlCommand cmd = new MySqlCommand(cmdText, cnn))
{
// Add both parameters to the same command
cmd.Parameters.Add("#name", MySqlDbType.VarChar).Value = s;
cmd.Parameters.Add("#sportsman_id", MySqlDbType.Int32).Value = Login.userID;
cnn.Open();
using(MySqlDataReader reader = cmd.ExecuteReader())
{
// get sum from the first result
if(reader.Read()) burned += Convert.ToInt32(reader[0]);
// if there is a second resultset, go there
if(reader.NextResult())
if(reader.Read())
burned += Convert.ToInt32(reader[0]);
}
}
Your issues could be around closing a connection and then trying to open it again. Either way it's fairly inefficient to be closing and opening connections.
MySqlCommand cmd = new MySqlCommand("SELECT name,calorificValue FROM myfitsecret.food where name=#name", cnn);
string s = (comboBox1.SelectedItem).ToString();
cmd.Parameters.AddWithValue("#name",s);
MySqlCommand cmd2 = new MySqlCommand("SELECT SUM(daily_gained) FROM myfitsecret.calorie_tracker where sportsman_id=#sportsman_id", cnn);
cmd2.Parameters.AddWithValue("#sportsman_id", Login.userID);
cnn.Open();
MySqlDataReader rd = cmd.ExecuteReader();
if (rd.HasRows) // if entered username and password have data
{
while (rd.Read()) // while the reader can read
{
burned += int.Parse(rd["calorificValue"].ToString());
}
}
burned = cmd2.ExecuteScalar();
MessageBox.Show(burned+"");
cnn.Close();

C# checking if order number already exists

I've been looking into How to check user id already exists to see how to do this.
I am trying to get this working in my code, however it's not working. I don't get errors or something, but it just write data in database even if order number already exists.
The function:
private void createorderButton_Click(object sender, EventArgs e)
{
SqlConnection myConnection = dbHelper.initiallizeDB();
String query = "INSERT INTO testtabel (knaam, korder) VALUES ('" + knaamTextBox.Text + "','" + kordernrTextBox.Text + "')";
SqlCommand sqlCommand = new SqlCommand(query, myConnection);
SqlCommand cmd = new SqlCommand("select * from testtabel where korder = #korder", myConnection);
SqlParameter param = new SqlParameter();
param.ParameterName = "#korder";
param.Value = kordernrTextBox.Text;
cmd.Parameters.Add(param);
//sqlCommand.Connection.Open();
SqlDataReader reader = sqlCommand.ExecuteReader();
if (reader.HasRows)
{
MessageBox.Show("Order already exist");
}
else
{
reader.Close();
}
// opens execute non query
int rows_inserted = sqlCommand.ExecuteNonQuery();
if (rows_inserted > 0)
{
label2.Text = "Order has been created";
}
else
{
Console.Write("Oops! Something wrong!");
}
}
Sorry for this kinda well known and duplicated question, but for some reason I can't get it working.
You called the wrong command, change
SqlDataReader reader = sqlCommand.ExecuteReader();
to
SqlDataReader reader = cmd.ExecuteReader();
The problem is here:
SqlDataReader reader = sqlCommand.ExecuteReader();
You should execute the other command first
SqlCommand cmd = new SqlCommand("select * from testtabel where korder = #korder", myConnection);
The latter command, when will be executed will tell you if there is any record in the testtabel table. If there is, then you should show the message:
Order already exist
Otherwise, you will execute your first command, that will insert the rows.
By the way, please try to avoid string concatenation, when you write sql queries. It is one of the most well known security holes. You code is open to SQL injections. You could use parameterized queries:
String query = "INSERT INTO testtabel (knaam, korder) VALUES (#knaam, #korder)";
SqlCommand sqlCommand = new SqlCommand(query, myConnection);
sqlCommand.Parameters.Add(new SqlParamete("#knaam",knaamTextBox.Text));
sqlCommand.Parameters.Add(new SqlParamete("#korder",kordernrTextBox.Text));
While your code is full of problems (magic pushbutton, SQL injections, absence of usings), there is main one. The approach you want to implement will fail on concurrent inserts, and must not be used.
Imagine, that two users run this code against the same database, using the same korder value:
1st executes SELECT - record with the given value doesn't exist;
2nd executes SELECT - record with the given value doesn't exist;
1st executes INSERT - record with the given value does exist;
2nd executes INSERT - ooops... we have a duplicate;
To avoid duplicates you must use unique indexes in database. Do not rely on your code.
You check HasRows for INSERT INTO testtabel bla...bla..bla.. not for `elect * from testtabel where korder'
Maybe you can use this (it comes from my head and not compiled, please adjust it with your own case)
private void createorderButton_Click(object sender, EventArgs e)
{
SqlConnection myConnection = dbHelper.initiallizeDB();
String query = "INSERT INTO testtabel (knaam, korder) VALUES ('" + knaamTextBox.Text + "','" + kordernrTextBox.Text + "')";
SqlCommand sqlCommand = new SqlCommand(query, myConnection);
SqlCommand cmd = new SqlCommand("select * from testtabel where korder = #korder", myConnection);
SqlParameter param = new SqlParameter();
param.ParameterName = "#korder";
param.Value = kordernrTextBox.Text;
//sqlCommand.Connection.Open();
SqlDataReader cmdReader = sqlCommand.ExecuteReader();
if (cmdReader.HasRows)
{
MessageBox.Show("Order already exist");
}
else
{
cmdReader.Close();
}
SqlDataReader reader = sqlCommand.ExecuteReader();
// opens execute non query
int rows_inserted = sqlCommand.ExecuteNonQuery();
if (rows_inserted > 0)
{
label2.Text = "Order has been created";
}
else
{
Console.Write("Oops! Something wrong!");
}
}

I don't get the while loop executed

I can't make out what is the mistake. I wanted to retrieve a record from the database table and give them out. There are 9 fields in my table. The data of the second field is the search word. There can be more than one record for the same data. If there are many, then it must show each record at a time. How is it possible to code it?
I use C#.Net for logic and Ms Access for the back end(Database)
This is my code:
string[] arr = new string[9];
OleDbConnection con = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="C:\PassWordSaver\Passwords.mdb;Persist Security Info=True;");
con.Open();
OleDbCommand cmd = new OleDbCommand("SELECT * FROM pwd Where Title = '"+textBox2+"'", con);
OleDbDataReader reader = cmd.ExecuteReader();
reader.Read();
//while (reader.Read())
//{
for (int i = 0; i < 9; i++)
{
arr[i] = reader.GetValue(i).ToString();
MessageBox.Show("The New data is " + arr[i] + ".", "Created", MessageBoxButtons.OK);
}
//}
reader.Close();
MessageBox.Show("Data Added Successfully. " + arr[2] + " is the user name.", "Created", MessageBoxButtons.OK);
OleDbCommand cmd = new OleDbCommand("SELECT * FROM pwd Where Title = '"+textBox2+"'", con);
Should read:
OleDbCommand cmd = new OleDbCommand("SELECT * FROM pwd Where Title = '"+textBox2.Text+"'", con);
The reason you aren't entering your while loop is that the condition isn't being met to begin with. There is nothing for myReader to read. However, I don't understand why you don't get an error when you run that telling you that you can't convert a textbox control to a string.
First of all you're getting into the loop because your query doesn't return any results, and second of all you might want to try and put some parameters on this query like so:
OleDbCommand cmd = new OleDbCommand("SELECT * FROM pwd Where Title = ?", con);
cmd.Parameters.Add(textBox2.Text); // I assume you mean textBox2.Text
May be it will be a silly answer but I think you are trying to send query by taking the value from textbox.Text property. But on the code you are trying to get directly Textbox
OleDbCommand cmd = new OleDbCommand("SELECT * FROM pwd Where Title = '"+textBox2+"'", con);
I think you can update as follows
OleDbCommand cmd = new OleDbCommand("SELECT * FROM pwd Where Title = '"+textBox2.Text+"'", con);

Categories

Resources