ionline - class, string myname
private static void SetOnlineStatus(PacketHeader header, Connection connection, ionline message)
{
Console.WriteLine("Check online: " + message.myname);
MySqlCommand mycmd = new MySqlCommand();
mycmd.CommandText = "SELECT * FROM users WHERE username = ?user";
mycmd.Connection = mconnection;
mycmd.Parameters.AddWithValue("user", message.myname);
MySqlDataReader Reader = mycmd.ExecuteReader();
while (Reader.Read())
{
Console.WriteLine("Check online: " + message.myname+" "+GetDBString("username",Reader));
MySqlCommand mycmd2 = new MySqlCommand();
mycmd2.CommandText = "UPDATE users SET online = 0 WHERE userid = #user2";
mycmd2.Parameters.AddWithValue("#user2", Reader.GetInt32("userid"));
mycmd2.Connection = mconnection;
Console.WriteLine(mycmd2.ExecuteNonQuery().ToString());
}
}
Mysql request "mycmd2" isn't executed . What in my query not the correct?
While a DataReader is open its connection is busy serving the reader.
The connection cannot be used to make other operations on the database.
You should get an exception though.
If your first query returns zero or one row, then you could simplify your code using the ExecuteScalar method and removing the need to use a MySqlDataReader
Console.WriteLine("Check online: " + message.myname);
MySqlCommand mycmd = new MySqlCommand();
mycmd.CommandText = "SELECT userid FROM users WHERE username = ?user";
mycmd.Connection = mconnection;
mycmd.Parameters.AddWithValue("user", message.myname);
object result = mycmd.ExecuteScalar();
if(result != null)
{
int userID = Convert.ToInt32(result);
MySqlCommand mycmd2 = new MySqlCommand();
mycmd2.CommandText = "UPDATE users SET online = 0 WHERE userid = #user2";
mycmd2.Parameters.AddWithValue("#user2", userID);
mycmd2.Connection = mconnection;
mycmd2.ExecuteNonQuery();
}
Related
Basically I want to check, using c#, if there is a username in the database already existing. If there is not-it must be created.
Below is the code that is doing exactly that(only the checking part matters in my opinion, but I have added the code for the adding part anyways)
Problem is that no matter what-if it exists or not, it always returns -1
public Boolean checkUser()
{
var connection = new MySqlConnection("Server=127.0.0.1;Database=book_library;user=root;password=root2");
var table = new DataTable();
connection.Open();
string checkUsernameQuery = "SELECT * FROM accounts WHERE username = 'usernameInputField.Text'";
var adapter = new MySqlDataAdapter();
MySqlCommand command = new MySqlCommand(checkUsernameQuery, connection);
//command.Parameters.Add("#username", MySqlDbType.VarChar).Value = usernameInputField.Text;
adapter.SelectCommand = command;
adapter.Fill(table);
if (table.Rows.Count > 0)
{
return true;
}
else
{
return false;
}
}
Here is the adding part(just adding it, but it is not too related with the problem)
private void registerIconButton_Click(object sender, EventArgs e)
{
checkUser();
var connection = new MySqlConnection("Server=127.0.0.1;Database=book_library;user=root;password=root2");
connection.Open();
string insertQuery = "INSERT INTO `accounts` (username, password, email) VALUES ('" + usernameInputField.Text + "','" + passwordInputField.Text + "','" + emailInputField.Text + "')";
MySqlCommand command = new MySqlCommand(insertQuery, connection);
command.Parameters.Add("#username", MySqlDbType.VarChar).Value = usernameInputField.Text;
command.Parameters.Add("#password", MySqlDbType.VarChar).Value = passwordInputField.Text;
command.Parameters.Add("#email", MySqlDbType.VarChar).Value = emailInputField.Text;
if (checkUser())
{
MessageBox.Show("This username already exists!");
}
else
{
if (command.ExecuteNonQuery() == 1)
{
}
else
{
MessageBox.Show("ERROR");
}
}
connection.Close();
}
Connections and Commands are disposable so you should put them inside using blocks to deterministically clean up resources.
If you just want to know if something exists, you can use ExecuteScalar instead of using a heavy-weight adapter.
Then just return the result of the expression != null to get your boolean that indicates if the user is there or not.
using(var connection = new MySqlConnection("Server=127.0.0.1;Database=book_library;user=root;password=root2"))
using(var cmd = connection.CreateCommand())
{
connection.Open();
string checkUsernameQuery = "SELECT TOP 1 username FROM accounts WHERE username = #p1";
cmd.Parameters.Add(new MySqlParameter("#p1", MySqlDbType.VarChar).Value = usernameInputField.Text;
var user = cmd.ExecuteScalar();
return user != null;
}
I am trying to update my database while reading data from it, but the reader gets closed and it throws the exception that it can''t read wen reader is closed. Is the update.ExecuteNonQuery() closing the reader method?
If i get rid of linescon.Close(); con.Open(); i get There is already an open DataReader associated with this Connection which must be closed first.
So how can i update my database records while keep the reading opened?
{
public class MySqlReadUpdate
{
public int Id { get; set; }
public string Notes { get; set; }
}
static void Main()
{
List<MySqlReadUpdate> dbData = new List<MySqlReadUpdate>();
var config = "server=localhost;user id=root; database=restaurants; pooling=false;SslMode=none;Pooling=True";
MySqlConnection con = new MySqlConnection(config);
MySqlDataReader reader = null;
string query = "SELECT id, notes FROM customers";
MySqlCommand command = new MySqlCommand(query, con);
con.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
MySqlReadUpdate newMySqlReadUpdate = new MySqlReadUpdate();
newMySqlReadUpdate.Id = (int)reader["id"];
newMySqlReadUpdate.Notes = (string)reader["notes"];
string note = newMySqlReadUpdate.Notes;
var notesplit = note.Split(' ', '\n')[1];
dbData.Add(newMySqlReadUpdate);
Console.WriteLine(newMySqlReadUpdate.Id);
Console.WriteLine(newMySqlReadUpdate.Notes);
Console.WriteLine(note);
Console.WriteLine(notesplit);
con.Close();
con.Open();
string query2 = "UPDATE customers SET notes='" + notesplit + "' WHERE id='" + newMySqlReadUpdate.Id + "';";
MySqlCommand update = new MySqlCommand(query2, con);
update.ExecuteNonQuery();
}
con.Close();
Console.WriteLine("Finished!");
Console.Read();
}
}
}
You cannot close a connection like you are, because the data reader depends on it. Once you call con.Close you break it. That's why you see an exception the next time it gets to reader.Read().
What you want is to add MultipleActiveResultSets=True in the configuration string; however, as we discussed in the comments it's apparently still not supported in MySQL. Therefore, the answer is two connection instances.
List<MySqlReadUpdate> dbData = new List<MySqlReadUpdate>();
var config = "server=localhost;user id=root;database=restaurants;pooling=false;SslMode=none";
MySqlConnection con = new MySqlConnection(config);
MySqlConnection cmdCon = new MySqlConnection(config);
MySqlDataReader reader = null;
string query = "SELECT id, notes FROM customers";
MySqlCommand command = new MySqlCommand(query, con);
con.Open();
cmdCon.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
MySqlReadUpdate newMySqlReadUpdate = new MySqlReadUpdate();
newMySqlReadUpdate.Id = (int)reader["id"];
newMySqlReadUpdate.Notes = (string)reader["notes"];
string note = newMySqlReadUpdate.Notes;
var notesplit = note.Split(' ', '\n')[1];
dbData.Add(newMySqlReadUpdate);
Console.WriteLine(newMySqlReadUpdate.Id);
Console.WriteLine(newMySqlReadUpdate.Notes);
Console.WriteLine(note);
Console.WriteLine(notesplit);
string query2 = "UPDATE customers SET notes='" + notesplit + "' WHERE id='" + newMySqlReadUpdate.Id + "';";
MySqlCommand update = new MySqlCommand(query2, cmdCon);
update.ExecuteNonQuery();
}
con.Close();
cmdCon.Close();
Console.WriteLine("Finished!");
Console.Read();
I would recommend that you also modify your code to use using statements or wrap things in try-finally blocks.
How do I go about setting a MySQL query and parameters based on a condition?
I want different queries based on 'questionSource' as shown below.
However, in my code below, 'cmd' does not exist in the current context.
Alternatively, I could have two different functions for each condition and call the necessary function as required but I imagine there must be a way to have conditions within a connection.
//validation checks
else
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
string questionSource = Session["QuestionSource"].ToString();
string cmdText = "";
if (questionSource.Equals("S"))
{
cmdText += #"SELECT COUNT(*) FROM questions Q
JOIN users U
ON Q.author_id=U.user_id
WHERE approved='Y'
AND role=1
AND module_id=#ModuleID";
MySqlCommand cmd = new MySqlCommand(cmdText, conn);
cmd.Parameters.Add("#ModuleID", MySqlDbType.Int32);
cmd.Parameters["#ModuleID"].Value = Convert.ToInt32(Session["TestModuleID"]);
}
else if (questionSource.Equals("U"))
{
cmdText += "SELECT COUNT(*) FROM questions WHERE approved='Y' AND module_id=#ModuleID AND author_id=#AuthorID;";
MySqlCommand cmd = new MySqlCommand(cmdText, conn);
cmd.Parameters.Add("#ModuleID", MySqlDbType.Int32);
cmd.Parameters["#ModuleID"].Value = Convert.ToInt32(Session["TestModuleID"]);
cmd.Parameters.Add("#AuthorID", MySqlDbType.Int32);
cmd.Parameters["#AuthorID"].Value = Convert.ToInt32(Session["UserID"]);
}
int noOfQuestionsAvailable = 0;
int noOfQuestionsWanted = Convert.ToInt32(ddlNoOfQuestions.SelectedValue);
try
{
conn.Open();
noOfQuestionsAvailable = Convert.ToInt32(cmd.ExecuteScalar());
if (noOfQuestionsAvailable < noOfQuestionsWanted)
{
lblError.Text = "There are not enough questions available to create a test.";
}
else
{
Session["TestName"] = txtName.Text;
Session["NoOfQuestions"] = ddlNoOfQuestions.SelectedValue;
Session["QuestionSource"] = rblQuestionSource.SelectedValue;
Session["TestModuleID"] = ddlModules.SelectedValue;
Response.Redirect("~/create_test_b.aspx");
}
}
catch
{
lblError.Text = "Database connection error - failed to get module details.";
}
finally
{
conn.Close();
}
}
declare cmd before if
MySqlCommand cmd = new MySqlCommand("",connStr);
and in each part of if
cmd.CommandText=cmdText;
other suggestion: add
cmd.Parameters.Add("#ModuleID", MySqlDbType.Int32);
cmd.Parameters["#ModuleID"].Value = Convert.ToInt32(Session["TestModuleID"]);
always before if because it is used in the same way in if and else part
You just have to move the declaration of the cmd outside the if block:
//validation checks
else
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
string questionSource = Session["QuestionSource"].ToString();
string cmdText = "";
MySqlCommand cmd; // <-- here
if (questionSource.Equals("S"))
{
cmdText += #"SELECT COUNT(*) FROM questions Q
JOIN users U
ON Q.author_id=U.user_id
WHERE approved='Y'
AND role=1
AND module_id=#ModuleID";
cmd = new MySqlCommand(cmdText, conn); // remove MySqlCommand here
cmd.Parameters.Add("#ModuleID", MySqlDbType.Int32);
cmd.Parameters["#ModuleID"].Value = Convert.ToInt32(Session["TestModuleID"]);
}
else if (questionSource.Equals("U"))
{
cmdText += "SELECT COUNT(*) FROM questions WHERE approved='Y' AND module_id=#ModuleID AND author_id=#AuthorID;";
cmd = new MySqlCommand(cmdText, conn); // remove MySqlCommand here
cmd.Parameters.Add("#ModuleID", MySqlDbType.Int32);
cmd.Parameters["#ModuleID"].Value = Convert.ToInt32(Session["TestModuleID"]);
cmd.Parameters.Add("#AuthorID", MySqlDbType.Int32);
cmd.Parameters["#AuthorID"].Value = Convert.ToInt32(Session["UserID"]);
}
int noOfQuestionsAvailable = 0;
int noOfQuestionsWanted = Convert.ToInt32(ddlNoOfQuestions.SelectedValue);
try
{
conn.Open();
noOfQuestionsAvailable = Convert.ToInt32(cmd.ExecuteScalar());
if (noOfQuestionsAvailable < noOfQuestionsWanted)
{
lblError.Text = "There are not enough questions available to create a test.";
}
else
{
Session["TestName"] = txtName.Text;
Session["NoOfQuestions"] = ddlNoOfQuestions.SelectedValue;
Session["QuestionSource"] = rblQuestionSource.SelectedValue;
Session["TestModuleID"] = ddlModules.SelectedValue;
Response.Redirect("~/create_test_b.aspx");
}
}
catch
{
lblError.Text = "Database connection error - failed to get module details.";
}
finally
{
conn.Close();
}
}
Just move the declaration of the MySqlCommand outside the if/else blocks so you could use it in the final try where you execute the command
//validation checks
else
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
using(MySqlConnection conn = new MySqlConnection(connStr))
using(MySqlCommand cmd = conn.CreateCommand())
{
// Don't need to associate the command to the connection
// Already done by the CreateCommand above, just need to set
// the parameters and the command text
if (questionSource.Equals("S"))
{
cmdText = #"....."
cmd.CommandText = cmdText;
....
}
else if (questionSource.Equals("U"))
{
cmdText = "........."
cmd.CommandText = cmdText;
....
}
try
{
conn.Open();
noOfQuestionsAvailable = Convert.ToInt32(cmd.ExecuteScalar());
....
}
}
}
Notice also that you should use the using statement to be sure that your connection and your command are propertly closed and disposed.
Bussiness Access Layer :
public static int login(string userlogin, string pwdlogin)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
int id = 0;
string selectstr = "SELECT UserName, Password FROM Registration WHERE UserName = '" + userlogin.Trim() + "' AND Password = '" + pwdlogin.Trim() + "'";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = selectstr;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
id = cmd.ExecuteNonQuery();
cmd = null;
con.Close();
return id;
}
Login.cs
protected void Button1_Click(object sender, EventArgs e)
{
int id = BusinessAccessLayer.login(userlogin.Text.Trim(), pwdlogin.Text.Trim());
if (id > 0)
{
message.Text = " valid";
}
else
{
message.Text = "in valid";
}
}
Okay, there are multiple things wrong here:
1) You should use using statements to make sure you close your connection and command even if exceptions are thrown
2) You should use parameterized SQL instead of putting the values directly into your SQL statement, to avoid SQL Injection Attacks
3) You appear to be storing passwords in plain text. Don't do that. Use a salted hash or something similar (ideally something slow to compute).
4) You're ignoring .NET naming conventions; methods should be in PascalCase
5) Your SQL never looks at any field which appears to be related to the user ID. It's not clear what you expect ExecuteNonQuery to return, but if you want the actual ID, you'll need to refer to it in the SQL. (Even if initially you just want to know whether or not the user's password is valid, I strongly suspect that at some point you'll want to user the real user ID, so you should make your code return it. If you really only want to know whether or not the password is valid, you should change the method's return type to bool.)
6) You're using ExecuteNonQuery when your command clearly is a query. Either use ExecuteReader or ExecuteScalar instead. (ExecuteNonQuery is meant for insert, delete and update statements, and it returns you the number of rows affected by the command.)
So something like:
public static int Login(string user, string password)
{
using (var conn = new SqlConnection(GetConnectionString()))
{
conn.Open();
string sql = "select Id, PasswordHash from logins where Username=#Username";
using (var command = new SqlCommand(sql))
{
command.Parameters.Add("#Username", SqlDbType.NVarChar).Value = user;
using (var reader = command.ExecuteRead())
{
if (reader.Read())
{
int id = reader.GetInt32(0);
string hash = reader.GetString(1);
// TODO: Hash provided password with the same salt and compare
// results
if (CheckPassword(password, hash))
{
return id;
}
}
return 0; // Or use an int? return type and return null
}
}
}
}
The ExecuteNonQuery is used for For UPDATE, INSERT, and DELETE statements.
For SELECT statements, use ExecuteReader
public static int login(string userlogin, string pwdlogin)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
int id = 0;
string selectstr = "SELECT UserName, Password FROM Registration WHERE UserName = '" + userlogin.Trim() + "' AND Password = '" + pwdlogin.Trim() + "'";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = selectstr;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
id++;
}
cmd = null;
reader.Close();
con.Close();
return id;
}
You can't use .ExecuteNonQuery if you want a result. Use .ExecuteReader.
public static int login(string userlogin, string pwdlogin)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
int id = 0;
string selectstr = "SELECT UserId FROM Registration WHERE UserName = '" + userlogin.Trim() + "' AND Password = '" + pwdlogin.Trim() + "'";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = selectstr;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
SqlDataReader reader = cmd.ExecuteReader();
reader.Read();
id = reader.GetInt32("UserId");
reader.Close();
con.Close();
return id;
}
I've been trawling through pages and pages on the internet for days now trying different approaches and I'm still not sure how I should be doing this.
On my third InsertCommand, I'd like to reference a column on the other 2 tables.
// Populate a DataSet from multiple Tables... Works fine
sqlDA = new SqlDataAdapter();
sqlDA.SelectCommand = new SqlCommand("SELECT * FROM hardware", sqlConn);
sqlDA.Fill(ds, "Hardware");
sqlDA.SelectCommand.CommandText = "SELECT * FROM software";
sqlDA.Fill(ds, "Software");
sqlDA.SelectCommand.CommandText = "SELECT * FROM join_hardware_software";
sqlDA.Fill(ds, "HS Join");
// After DataSet has been changed, perform an Insert on relevant tables...
updatedDs = ds.GetChanges();
SqlCommand DAInsertCommand = new SqlCommand();
DAInsertCommand.CommandText = "INSERT INTO hardware (host, model, serial) VALUES (#host, #model, #serial)";
DAInsertCommand.Parameters.AddWithValue("#host", null).SourceColumn = "host";
DAInsertCommand.Parameters.AddWithValue("#model", null).SourceColumn = "model";
DAInsertCommand.Parameters.AddWithValue("#serial", null).SourceColumn = "serial";
sqlDA.InsertCommand = DAInsertCommand;
sqlDA.Update(updatedDs, "Hardware"); // Works Fine
DAInsertCommand.Parameters.Clear(); // Clear parameters set above
DAInsertCommand.CommandText = "INSERT INTO software (description) VALUES (#software)";
DAInsertCommand.Parameters.AddWithValue("#software", null).SourceColumn = "description";
sqlDA.InsertCommand = DAInsertCommand;
sqlDA.Update(updatedDs, "Software"); // Works Fine
DAInsertCommand.Parameters.Clear(); // Clear parameters set above
DAInsertCommand.CommandText = "INSERT INTO join_hardware_software (hardware_id, software_id) VALUES (#hardware_id, #software_id)";
// *****
DAInsertCommand.Parameters.AddWithValue("#hardware_id", null).SourceColumn = "?"; // I want to set this to be set to my 'hardware' table to the 'id' column.
DAInsertCommand.Parameters.AddWithValue("#software_id", null).SourceColumn = "?"; // I want to set this to be set to my 'software' table to the 'id' column.
// *****
sqlDA.InsertCommand = DAInsertCommand;
sqlDA.Update(updatedDs, "HS Join");
Could somebody please tell me where I am going wrong and how I could potentially overcome this? Many thanks! :)
With regards to your comments this seems to be one of those occasions where if you and I were sat next to each other we'd get this sorted but it's a bit tricky.
This is code I've used when working with SqlConnection and SqlCommand. There might be stuff here that would help you.
public static void RunSqlCommandText(string connectionString, string commandText) {
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand comm = conn.CreateCommand();
try {
comm.CommandType = CommandType.Text;
comm.CommandText = commandText;
comm.Connection = conn;
conn.Open();
comm.ExecuteNonQuery();
} catch (Exception ex) {
System.Diagnostics.EventLog el = new System.Diagnostics.EventLog();
el.Source = "data access class";
el.WriteEntry(ex.Message + ex.StackTrace + " SQL '" + commandText + "'");
} finally {
conn.Close();
comm.Dispose();
}
}
public static int RunSqlAndReturnId(string connectionString, string commandText) {
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand comm = conn.CreateCommand();
int id = -1;
try {
comm.CommandType = CommandType.Text;
comm.CommandText = commandText;
comm.Connection = conn;
conn.Open();
var returnvalue = comm.ExecuteScalar();
if (returnvalue != null) {
id = (int)returnvalue;
}
} catch (Exception ex) {
System.Diagnostics.EventLog el = new System.Diagnostics.EventLog();
el.Source = "data access class";
el.WriteEntry(ex.Message + ex.StackTrace + " SQL '" + commandText + "'");
} finally {
conn.Close();
comm.Dispose();
}
return id;
}