When I run this code, the following error occurs
ExecuteNonQuery: CommandText property has not been initialized
Code:
con.Open();
SqlCommand cmd = con.CreateCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
if (Request.QueryString["search"] != null)
{
cmd.CommandText = "Select * from Products where ProductName like('%" + Request.QueryString["search"].ToString() + "%')";
}
cmd.ExecuteNonQuery();
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
dlProduct.DataSource = dt;
dlProduct.DataBind();
con.Close();
This would happen if you didn't have a search query-string parameter - you would never assign to CommandText.
However: please please please never write code like this; this is a SQL Injection hole that would let anyone own your database trivially. Please use ADO.NET parameters, or data access tools that do it for you.
Example:
string q = Request.QueryString["search"] ?? "";
cmd.CommandText = "Select * from Products where ProductName like N'%' + #q + N'%'";
cmd.Parameters.AddWithValue("#q", q);
Also: the cmd.ExecuteNonQuery(); does nothing useful - so just throw that away.
Since you are setting CommandText conditionally and the condition is false thats why you are getting error. Ensure you have search in querystring and also use parameterized query instead of embedding the value in queries to prevent sql injection
if (Request.QueryString["search"] != null)
{
cmd.CommandText = "Select * from Products where ProductName like('%" + Request.QueryString["search"].ToString() + "%')";
}
Related
This question already has answers here:
Return value of a select statement
(7 answers)
Closed 5 years ago.
I am trying To get ID against selected name in Drop Down list by using select query but it always returns the value "-1" instead of relevant result.
SqlCommand cmd2 = con.CreateCommand();
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "Select Pid From Provinces where Pname = '" + pr + "'";
cmd2.CommandText = "Select Pid From Provinces where Pname = '" + prov.Text + "'";
int pid = cmd2.ExecuteNonQuery();
You need to use ExecuteScalar instead of ExecuteNonQuery
int pid = Convert.ToInt32(cmd2.ExecuteScalar());
For more details please refer Link
The reason is that ExecuteNonQuery doesn't return the database value when using a Select command - It returns a return code for success or failure.
If you want to read the database value, use the following code. Note that I used an SqlParameter instead of your parameter concatenation, which can cause SQL injections and is a poor practice:
SqlCommand cmd2 = con.CreateCommand();
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "Select Pid From Provinces where Pname=#pr";
cmd2.Parameters.Add(new SqlParameter("pr", pr));
int result = Convert.ToInt32(cmd2.ExecuteScalar());
Alternativly, you can use fill a DataTable with multiple results:
SqlCommand cmd2 = con.CreateCommand();
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "Select Pid From Provinces where Pname=#pr";
cmd2.Parameters.Add(new SqlParameter("pr", pr));
SqlConnection Connection = new SqlConnection(ConnectionString);
SqlDataAdapter adp = new SqlDataAdapter(cmd2);
// Create a new datatable which will hold the query results:
DataTable dt = new DataTable();
Connection.Open();
// Fill a datatable with the query results:
adp.Fill(dt);
Connection.Close();
Let me add few notes for you before answer the question, You should aware about the usage of ExecuteNonQuery, and why other peoples refer ExecuteScalar for you. here is the difference you have to note.
ExecuteNonQuery() does not return data at all: only the number of rows affected by an insert, update, or delete
ExecuteScalar() only returns the value from the first column of the first row of your query.
There is few more things I want to remind you, As a developer we won't give the key to hackers through SqlInjection, for that we should use parameterization like the following:
using(SqlCommand cmdSql = con.CreateCommand())
{
cmdSql.CommandType = CommandType.Text;
cmdSql.CommandText = "Select Pid From Provinces where Pname =#Pname";
cmdSql.Parameters.Add("#Pname ", SqlDbType.VarChar).Value= prov.Text;
int pid = Convert.ToInt32(cmdSql.ExecuteScalar());
}
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!");
}
}
Why my code show this message
Data type mismatch in criteria expression.
The attribute Fine is in number datatype.
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string cq = "select sum(Fine) from Studentbook where Student_ID='" + textsearch.Text + "'";
command.CommandText = cq;
int a = Convert.ToInt32(command.ExecuteScalar());
connection.Close();
MessageBox.Show(a.ToString(), "Your FINE is", MessageBoxButtons.OK);
Other than possible SQL Injection vulnerability; the said error could be because of the WHERE part in your query; where Student_ID is number and you are trying to compare it with string type data.
where Student_ID='" + textsearch.Text + "'"
Considering that your Student_ID is of INT or NUMBER type column change your code to be like below. Notice the use of parameterized query to avoid SQL Injection
string sql = "select sum(Fine) from Studentbook where Student_ID = #studentid";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("#studentid", Convert.ToInt32(textsearch.Text.Trim()));
Okay basically I have a SQL Server database that has details in it.
Column names: Student_Id, Student_name, Unit_number, Unit_grade
I would like to query this database using two textboxes where you enter the id and unit_number and it will return the results in a message box when a button is clicked.
Where the question marks in the code are is where I am unsure of how to display a message box with the result. Unless this is completely the wrong way of doing things, I am only starting out with SQL in C#
I shouldn't be prone to SQL Injection using parameters as far as I know?
try
{
string str = "SELECT * FROM Students WHERE (Student_Id, Unit_number LIKE '%' + #search + '%')";
SqlCommand command = new SqlCommand(str, connect);
command.Parameters.Add("#search", SqlDbType.NVarChar).Value = textBox1.Text;
command.Parameters.Add("#search", SqlDbType.NVarChar).Value = textBox2.Text;
connect.Open();
command.ExecuteNonQuery();
SqlDataAdapter dataAdapt = new SqlDataAdapter();
dataAdapt.SelectCommand = command;
DataSet dataSet = new DataSet();
dataAdapt.Fill(dataSet, "Student_Id, Unit_number");
//?
//?
connect.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Your SQL is wrong in that your WHERE clause is syntactically incorrect. You probably want something like:
string str = "SELECT * FROM Students WHERE Student_ID = #id AND " +
"Unit_number LIKE #search";
This assumes that Student_ID is a text type. The syntax would be slightly different if it was a number.
You are trying to add the same parameter to the query twice, which you won't want. Instead you'd want two parameters to match with the new SQL definition:
command.Parameters.Add("id", SqlDbType.NVarChar).Value =
textBox1.Text;
command.Parameters.Add("search", SqlDbType.NVarChar).Value =
"%" + textBox2.Text + "%";
Running ExecuteNonQuery on the SqlCommand object doesn't do much for you as it is a query and you're not asking for the result back.
If you're only expecting one table back from your query, you'd probably be better off with a DataTable rather than a DataSet (the DataSet can contain many tables which is overkill for what you need).
try
{
string str = "SELECT * FROM Students WHERE Student_Id = #id AND " +
"Unit_number LIKE #search";
connect.Open();
SqlCommand command = new SqlCommand(str, connect);
command.Parameters.Add("id", SqlDbType.NVarChar).Value =
textBox1.Text;
command.Parameters.Add("search", SqlDbType.NVarChar).Value =
"%" + textBox2.Text + "%";
SqlDataAdapter dataAdapt = new SqlDataAdapter();
dataAdapt.SelectCommand = command;
DataTable dataTable = new DataTable();
dataAdapt.Fill(dataTable);
// At this point you should have a DataTable with some results in it.
// This is not going to be the best way of displaying data,
// but it should show you _something_
// It just iterates through the rows showing the columns
// which you've shown as being in your data.
foreach (DataRow dr in dataTable.Rows)
{
MessageBox.Show(String.Format("{0} - {1} - {2} - {3}",
dr["Student_Id"], dr["Student_name"],
dr["Unit_number"], dr["Unit_grade"]));
}
connect.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
EDITED to change the parameter handling as it didn't quite do what was needed. The % symbols are not part of the parameter rather than the SQL string.
Good day! I am having a hard time fixing this problem. I've been searching the answer for this but seemed to be very very hard to look for the most fitting answer.
i use this query to search for a tenant's name based on what the user inputs in the txtSearchRP textbox, it works very well to data with no apostrophe in it, however when the user searches for a name containing ' , it does not function well.
example: user inputs MAX'S to search MAX'S RESTAURANT
SELECT * from tenant WHERE (name LIKE '%" + txtSearchRP.Text + "%')
Thanks for your help in advance!
edit for more information:
I am actually passing the query to sqlDataSource to bind the gridview automatically after the user click THE BUTTON.
SqlDataSource3.SelectCommand = SELECT * from tenant WHERE (name LIKE '%" + txtSearchRP.Text + "%')
Try this
conn = new
SqlConnection("ConnectionString");
conn.Open();
SqlCommand cmd = new SqlCommand(
"SELECT * from tenant WHERE (name LIKE #tenant)", conn);
SqlParameter param = new SqlParameter();
param.ParameterName = "#tenant";
param.Value = "%" + txtSearchRP.Text + "%"; // you can use any wildcard operator
cmd.Parameters.Add(param);
SqlDataReader reader = cmd.ExecuteReader();
In addition to the answers already given, in some applications, you might need to consider escaping wildcards such as % in the input string provided by the user.
For example, if the user enters "25%", then matching on "%25%%" will return values that contain "25", rather than restricting to values that contain "25%".
You can escape wildcards as follows (for SQL Server):
string value = ... value entered by user;
value = value.Replace("[", "[[]");
value = value.Replace("_", "[_]");
value = value.Replace("%", "[%]");
Better way create storedprocedure
SP :
Create proc sp_Search( #txtSearch nvarchar(150))
as begin
SELECT * from tenant WHERE name like #txtSearch+'%'
end
Code behind :
string txtSearch = txtSearchRP.Text;
SqlDataReader dr;
using (SqlConnection conn = new SqlConnection(cn.ConnectionString))
{
using (SqlCommand cmdd = new SqlCommand())
{
cmdd.CommandType = CommandType.StoredProcedure;
cmdd.CommandText = "sp_Search";
cmdd.Parameters.AddWithValue("#txtSearch", txtSearch);
cmdd.Connection = conn;
conn.Open();
dr = cmdd.ExecuteReader(CommandBehavior.CloseConnection);
if (dr.HasRows)
{
while (dr.Read())
{
var name = dr["name"].ToString();
var location = dr["location"].ToString();
}
} dr.Close();
conn.Close();
}
}
Updated:
Write a function which returns datatable so that we can bind it to our gridview control as i did in code below
public DataTable bindGridView()
{
string txtSearch = txtSearchRP.Text;
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(cn.ConnectionString))
{
SqlCommand cmdd = new SqlCommand();
cmdd.CommandType = CommandType.StoredProcedure;
cmdd.CommandText = "sp_Search";
cmdd.Parameters.AddWithValue("#txtSearch", txtSearch);
cmdd.Connection = con;
con.Open();
SqlDataAdapter dap = new SqlDataAdapter(cmdd);
DataSet ds = new DataSet();
dap.Fill(ds);
dt = ds.Tables[0];
con.Close();
}
return dt;
}
On Button click : Call bindGridView() function for binding Gridview control
GridView1.DataSource = bindGridView();
GridView1.DataBind();
thanks to all who shared their knowledge and effort, finally got the answer through the String replace method
HERE'S THE 3-LINED CODE
string value = txtSearchRP.Text;
value = value.Replace("'", "['']");
sqlDataSource3.SelectCommand = "SELECT * from tenant WHERE (name LIKE '%" + value.ToString() +"%')";
through the joined effort, answers you posted here, we solve the problem in the simplest form :)