MySqlCommand Object reference not set to an instance of an object - c#

I want to update calorie_tracker table after burned value is calculated.Until cmd2 command it works.But while trying to cmd2 gives an error :Object reference not set to an instance of an object.How can I make this update in the same command(cmd) or is there any alternative?
string time = DateTime.Now.ToString("dd-MM-yyyy");
int burned = 0;
string s = (comboBox1.SelectedItem).ToString();
cnn.Open();
string cmdText = #"SELECT calorificValue
FROM myfitsecret.food
WHERE name=#name;
SELECT 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.String).Value = s;
cmd.Parameters.Add("#sportsman_id", MySqlDbType.String).Value = Login.userID;
using (MySqlDataReader reader = cmd.ExecuteReader())
{
// get sum from the first result
if (reader.Read()) burned += (Convert.ToInt32(reader[0])*int.Parse(textBox1.Text));
// if there is a second resultset, go there
if (reader.NextResult())
if (reader.Read())
burned += Convert.ToInt32(reader[0]);
}
cmd.Connection.Close();
MySqlCommand cmd2 = new MySqlCommand("update myfitsecret.calorie_tracker set daily_gained=#daily_gained where sportsman_id=#sportsman_id and Date=#Date");
cmd2.CommandType = CommandType.Text;
cmd2.Connection.Open();
cmd2.Parameters.AddWithValue("#daily_gained", burned);
cmd2.Parameters.AddWithValue("#Date", time);
cmd2.Parameters.Add("#sportsman_id", MySqlDbType.String).Value = Login.userID;
cmd2.ExecuteNonQuery();

You need to pass the connection to MySqlCommand before trying to open it like this:
cmd.Connection.Close();
MySqlCommand cmd2 = new MySqlCommand("update myfitsecret.calorie_tracker set daily_gained=#daily_gained where sportsman_id=#sportsman_id and Date=#Date",cnn);
cmd2.CommandType = CommandType.Text;
cmd2.Connection.Open();
I would also advise wrapping this command in a using statement as well.

Related

Issue in update statement

I am writing the following lines of code to update the data in access database.
using (OleDbConnection con = new OleDbConnection())
{
con.ConnectionString = String.Format(Queries.dbConnection, databasePath);
con.Open();
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = con;
cmd.CommandText = "update tblusers set password = #password where userId = #userId;";
cmd.CommandType = System.Data.CommandType.Text;
cmd.Parameters.AddWithValue("#userId", authResult.UserId);
cmd.Parameters.AddWithValue("#password", newPassword);
cmd.ExecuteNonQuery();
}
}
When this line runs cmd.ExecuteNonQuery(); I got the following error:
Syntax error in UPDATE statement
Am I missing anything?
Update - 2
using (OleDbConnection con = new OleDbConnection())
{
con.ConnectionString = String.Format(Queries.dbConnection, databasePath);
con.Open();
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = con;
cmd.CommandText = "update tblusers set password = ? where userId = ?;";
cmd.CommandType = System.Data.CommandType.Text;
cmd.Parameters.Add("p1", OleDbType.VarChar, 100).Value = newPassword;
cmd.Parameters.Add("p2", OleDbType.Integer).Value = authResult.UserId;
cmd.ExecuteNonQuery();
}
}
First of all: MS Access / OleDB does not used named parameters - but positional parameters. So the order in which you specify the parameters is very much relevant!
Second: OleDB uses the ? as a parameter placeholder.
So try this code:
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = con;
cmd.CommandText = "update tblusers set [password] = ? where userId = ?;";
cmd.CommandType = System.Data.CommandType.Text;
// parameters - do *NOT* use "AddWithValue", and specify in the *correct order*!
// since the parameters are *positional*, the name provided is irrelevant
cmd.Parameters.Add("p1", OleDbType.VarChar, 50).Value = newPassword;
cmd.Parameters.Add("p2", OleDbType.Integer).Value = authResult.UserId;
cmd.ExecuteNonQuery();
}

OleDbCommand in Using block: COM object that has been separated from its underlying RCW cannot be used

I got error "System.Runtime.InteropServices.InvalidComObjectException: 'COM object that has been separated from its underlying RCW cannot be used.'" ONLY when i execute OleDbCommand object in using block with parameters
using (OleDbCommand comm = new OleDbCommand())
{
comm.Connection = conn;
comm.CommandType = CommandType.Text;
string txt = "SELECT* FROM [ListForGroup] WHERE [email] = #email";
comm.Parameters.Add("#email", OleDbType.VarWChar).Value = userEmail;
comm.CommandText = txt;
conn.Open();
OleDbDataReader reader = comm.ExecuteReader();
List<ListForGroups> list = returnLists(reader);
conn.Close();
cmbSelectList.DataSource = list;
cmbSelectList.DisplayMember = "listName";
cmbSelectList.ValueMember = "listForGroupsID";
}
Does anyone know reason for that. I can resolve it to use OleDbCommand object with CommandText without parameters but i read that's bad idea. And i want to do it in using block to be sure that all reasources will be released.
I resolved this problem
using (OleDbConnection conn = new OleDbConnection(connString))
{
OleDbCommand comm = new OleDbCommand();
comm.Connection = conn;
comm.CommandType = CommandType.Text;
string txt = "SELECT* FROM [ListForGroup] WHERE [email] = #email";
comm.Parameters.Add("#email", OleDbType.VarWChar).Value = userEmail;
comm.CommandText = txt;
conn.Open();
OleDbDataReader reader = comm.ExecuteReader();
List<ListForGroups> list = returnLists(reader);
cmbSelectList.DataSource = list;
cmbSelectList.DisplayMember = "listName";
cmbSelectList.ValueMember = "listForGroupsID";
}
I don't know why I didn't create OleDbConnection in brackets next to using. Another when to resolve it is to close connection after using block.

C# SQL, Multiple Commands

I'm trying to write a method which should communicate with database, but I'm not sure if my approach is right.
public void dbWorkerLogin(int workerNumber) {
// Connection string stored in "conn"
if (!new SqlCommand("Some Command WHERE id=" +workernumber,conn).executeReader().HasRows)
{
new SqlCommand("exec STORED_PROCEDURE1 " + workerNumber, conn).ExecuteNonQuery();
new SqlCommand("exec STORED_PROCEDURE2 " + workerNumber, conn).ExecuteNonQuery();
}
else
{
new SqlCommand("exec STORED_PROCEDURE3 " + workerNumber,conn).ExecuteNonQuerry();
}
1) Is it ok to write it like this and start each SqlCommand with keyword new? Or should I do something like:
SqlCommand command = new SqlCommand(null, conn);
command = ...;
and then recycle the variable 'command' or this way?
using(SqlCommand cmd = new SqlCommand("COMMAND", conn);
2) Will my procedures work or should I use SqlCommand.Prepare() function that will covert my data into correct datatypes? eg. workerNumber is int, but in database it is stored as decimal.
using (SqlCommand cmd = new SqlCommand("STORED_PROCEDURE", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parametres.Add("#id", SqlDbType.Decimal).Value = workNumber;
cmd.Prepare();
cmd.ExecuteNonQuery();
}
Can you please somehow sum up what to use, what better not to? Unfortunately I can't test that first code because of limited access to DB so I'm not sure if it can be executed without errors or not.
Thank you for any help on this subject!
EDIT:
After a few hours I reach to this stage:
public int getWorkerNumber(string uniqueID)
{
using (conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dbConnect"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT number FROM worker WHERE workerID = #id",conn))
{
cmd.Parameters.Add("#id", SqlDbType.Decimal).Value = uniqueID;
using (SqlDataReader reader = cmd.ExecuteReader())
{
int answer;
while (reader.Read())
{
answer = (int)reader.GetDecimal(0);
}
return answer;
}
}
}
}
And this one:
public string dbLoginWorker(int workerNumber)
{
SqlCommand cmd;
SqlDataReader reader;
using (conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dbConnect"].ConnectionString))
{
conn.Open();
cmd = new SqlCommand("SELECT column FROM table WHERE id= #workernumber", conn);
cmd.Parameters.Add("#workernumber", SqlDbType.Decimal).Value = workerNumber;
reader = cmd.ExecuteReader();
if (!reader.HasRows)
{
cmd = new SqlCommand("STORED_PROCEDURE1", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal).Value = workerNumber;
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar).Value = "text";
cmd.Prepare();
reader.Close();
cmd.ExecuteNonQuery();
cmd.Dispose();
reader.Dispose();
return "procedure 1 executed";
else
{
cmd = new SqlCommand("STORED_PROCEDURE2", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal).Value = workerNumber;
cmd.Parameters.Add("#INT", SqlDbType.SmallInt).Value = 1;
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar).Value = "text";
cmd.Prepare();
reader.Close();
cmd.ExecuteNonQuery();
cmd.Dispose();
reader.Dispose();
return "procedure 2 executed";
}
}
}
Both methods are functional (if I did no mistake in rewriting :) ). I'm not sure which of these methods (1st or 2nd) are better in terms of stability and if this approach is better and more ressistant to SQL Injection. Can someone comment on this subject? Thank you again for any help!
1) It is best to always use USING blocks when possible. This includes SqlConnection, SqlCommand, SqlReader and other objects that implement IDisposable. USING blocks automatically close and dispose of the objects, so you do not have to do so.
2) I believe that you are using the Prepare() method in the wrong place. Look at the following StackOverflow article for proper usage:
PrepareMethodInstructions.
3) in the dbLoginWorker() method, the first query is just used to determine if rows are found. Therefore, I suggest changing the SELECT command to SELECT TOP 1 column FROM table WHERE id= #workernumber so that the query is faster and more efficient.
4) I do not believe your commands are subject to SQL Injection attacks because they are fully parameterized. Good job on that one.
5) As a general thought, I suggest reading up on refactoring techniques. Your dbLoginWorker() method could be made more readable and maintainable, as well as self-documenting, if you created three additional methods, one for each SQL command, and named them something appropriate. You could also setup a method for creating a connection based on a connection name, and you would not have as much duplicate code. For example:
public static SqlConnection GetConnection(string connectionName)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[connectionName].ConnectionString);
conn.Open();
return conn;
}
public string dbLoginWorker(int workerNumber)
{
using (conn = GetConnection("dbConnect"))
{
if (CanFindWorkerNumber(conn, workerNumber))
ExecuteProcedure1(conn);
else
ExecuteProcedure2(conn);
}
}
public bool CanFindWorkerNumber (SqlConnection conn, int workerNumber)
{
bool success = false;
using (SqlCommand cmd = new SqlCommand("SELECT TOP 1 column FROM table WHERE id= #workernumber", conn))
{
cmd.Parameters.Add("#workernumber", SqlDbType.Decimal);
cmd.Prepare();
cmd.Parameters[0].Value = workerNumber;
success = cmd.ExecuteScalar() != null;
}
return success;
}
public void ExecuteProcedure1(SqlConnection conn)
{
using (SqlCommand cmd = new SqlCommand("STORED_PROCEDURE1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal);
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar);
cmd.Prepare();
cmd.Parameters[0].Value = workerNumber;
cmd.Parameters[1].Value = "text";
cmd.ExecuteNonQuery();
}
}
public void ExecuteProcedure1(SqlConnection conn)
{
using (SqlCommand cmd = new SqlCommand("STORED_PROCEDURE1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal);
cmd.Parameters.Add("#INT", SqlDbType.SmallInt).Value);
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar);
cmd.Prepare();
cmd.Parameters[0] = workerNumber;
cmd.Parameters[1] = 1;
cmd.Parameters[2] = "text";
cmd.ExecuteNonQuery();
}
}
You could actually do this in one SQL commend. Right now you are pulling back a result set only to see if it has rows or not, then executing different commands based on that. You should be able to do that in one command, disposing of it and the connection appropriately:
var sql =
#"
IF EXISTS(Some Command WHERE id=#workernumber)
BEGIN
exec STORED_PROCEDURE1 #workernumber;
exec STORED_PROCEDURE2 #workernumber;
END
ELSE
exec STORED_PROCEDURE3 #workernumber;
";
Note that you're not vulnerable to SQL injection because you're not dealing with strings, only integers.

"executenonquery connection property has not been initialized"

SqlConnection cn = new SqlConnection(#"DataSource=dbedu.cs.vsb.cz\SQLDB;Persist Security Info=True;User ID=*****;Password=*******");
SqlCommand cmd = new SqlCommand();
string finish = DropDownListFi.SelectedValue;
cn.Open();
String Name = Request.QueryString["Name"];
cmd.CommandText = "UPDATE navaznost_ukolu SET finish=#finish where Name='" + Name + "'";
cmd.Parameters.Add(new SqlParameter("#finish", finish));
cmd.ExecuteNonQuery();
cmd.Clone();
The error message
Executenonquery connection property has not been initialized.
the problem with your current code is that you have not set the Connection property of the SqlCommand object. Try this,
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
and you must also parameterized the values set on the name
String Name = Request.QueryString["Name"];
cmd.CommandText = "UPDATE navaznost_ukolu SET finish=#finish where Name=#name";
cmd.Parameters.Add(new SqlParameter("#finish", finish));
cmd.Parameters.Add(new SqlParameter("#name", Name));
FULL CODE
string finish = DropDownListFi.SelectedValue;
String Name = Request.QueryString["Name"];
string connStr = #"DataSource=dbedu.cs.vsb.cz\SQLDB;
Persist Security Info=True;
User ID=*****;
Password=*******";
string sqlStatement = #"UPDATE navaznost_ukolu
SET finish = #finish
WHERE Name = #Name";
using (SqlConnection conn = new SqlConnection(connStr))
{
using(SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = sqlStatement;
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("#finish", finish));
cmd.Parameters.Add(new SqlParameter("#name", Name));
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch(SqlException e)
{
// do something with the exception
// do not hide it
// e.Message.ToString()
}
}
}
For proper coding
use using statement for propr object disposal
use try-catch block to properly handle objects
The error is self-explanatory, you have not assigned the connection to the command. You can use the constructor:
using(var cn = new SqlConnection(#"DataSource=dbedu.cs.vsb.cz\SQLDB;Persist Security Info=True;User ID=*****;Password=*******"))
using(var cmd = new SqlCommand(
"UPDATE navaznost_ukolu SET finish=#finish where Name=#Name"
, cn))
{
string finish = DropDownListFi.SelectedValue;
cn.Open();
String Name = Request.QueryString["Name"];
cmd.Parameters.AddWithValue("#finish", finish);
cmd.Parameters.AddWithValue("#Name", Name);
cmd.ExecuteNonQuery();
}
Note that i've also used a sql-parameter for the Name and using statements to ensure that anything implementing IDisposable gets disposed, even in case of an exception. This will also close the connection.

How to assign default value in a parameter?

I have the codes below that will display data from access database into textboxes of another form.
item items = new item();
Add_Order addorder = new Add_Order();
OleDbCommand cmd = new OleDbCommand("Select * from tblItems WHERE ItemName = #Item", connection);
cmd.Parameters.AddWithValue("#Item", items.ItemName1);
cmd.Connection = connection;
connection.Open();
cmd.ExecuteNonQuery();
cmd.Parameters.AddWithValue("#ItemID", addorder.tbItemID.Text);
cmd.Parameters.AddWithValue("#ItemName", addorder.tbName.Text);
cmd.Parameters.AddWithValue("#ItemPrice", addorder.tbPrice.Text);
OleDbDataReader read = cmd.ExecuteReader();
while (read.Read())
{
addorder.tbItemID.Text = read[0].ToString();
addorder.tbName.Text = read[1].ToString();
addorder.tbPrice.Text = read[2].ToString();
}
addorder.ShowDialog();
connection.Close();
the error says that
Parameter #Item has no default value
But I already assigned the value of #Item in this line
cmd.Parameters.AddWithValue("#Item", items.ItemName1);
I found some mistakes, you are retrieving some items. Then, Why you are using ExecuteNonquery() and some other parameters. Simply try this
cmd.Connection = connection;
connection.Open();
OleDbCommand cmd = new OleDbCommand("Select * from tblItems WHERE ItemName = #Item", connection);
cmd.Parameters.AddWithValue("#Item", items.ItemName1);
OleDbDataReader read = cmd.ExecuteReader();
while (read.Read())
{
addorder.tbItemID.Text = read[0].ToString();
addorder.tbName.Text = read[1].ToString();
addorder.tbPrice.Text = read[2].ToString();
}
connection.Close();
Make sure that items.ItemName1 has a valid entry. You can verify this by simply passing some values manually as
cmd.Parameters.AddWithValue("#Item", "some text");
Try this one:
cmd.Parameters.AddWithValue("#Item", OleDbType.VarChar).Value = items.ItemName1;
And why are you using this again after ExecuteNonQuery()..?
cmd.Parameters.AddWithValue("#ItemID", addorder.tbItemID.Text);
cmd.Parameters.AddWithValue("#ItemName", addorder.tbName.Text);
cmd.Parameters.AddWithValue("#ItemPrice", addorder.tbPrice.Text);
cmd.Parameters.Add(new OleDbParameter("item", OleDbType.VarChar, 32, "Item").Value = items.ItemName1;
^^^^^^^^^^^^^^^^^^
the point is to construct Parameter()

Categories