In this program I try to get data from SQL into a list of strings and show them in a messageBox. The program should start searching when I type one character in textBox and use this in the query as below:
string sql = " SELECT * FROM general WHERE element='" + textBox1.Text + "' OR element='" + textBox2.Text + "' OR element='" + textBox3.Text + "' OR element='" + textBox4.Text + "'";
MySqlConnection con = new MySqlConnection("host=localhost;user=mate;password=1234;database=element_database");
MySqlCommand cmd = new MySqlCommand(sql, con);
con.Open();
MySqlDataReader reader = cmd.ExecuteReader();
string rd;
rd = reader.ToString();
int i=0;
List<string> item = new List<string>();
while (reader.Read())
{
item.Add(rd["element"].ToString());//i got error in this line
}
for (i = 0; i < item.Count;i++ )
{
MessageBox.Show(item[i]);
}
What am I doing wrong?
What are you doing wrong? a bunch of things:
In your question you write you gen an error but don't tell us what it is.
Exceptions has messages for a reason: so that you will be able to know what went wrong.
As to your code:
You are concatenating values into your select statement instead of using parameterized queries. This creates an opening for sql injection attacks.
You are using an SqlConnection outside of a using statement.
You should always use the using statement when dealing with IDisposable objects.
You assume that rd["element"] always have a value.
If it returns as null from the database, you will get a null reference exception when using .ToString() on it. The proper way is to put it's value into a local variable and check if this variable is not null before using the .ToString() method.
You are using rd instead of reader in your code. the rd variable is meaningless, as it only contain the string representation of MySqlDataReader object.
You have declared rd as string. You probably meant to use the reader object in this loop instead:
while (reader.Read())
{
item.Add(reader["element"].ToString());// change "rd" to "reader"
}
I took the liberty of modifing the SQL to use an IN instead of multiple or statements as well as including the use of parameter into the query and not a string based approach. This should solve your problems.
string elem1 = "#elem1";
string elem2 = "#elem2";
string elem3 = "#elem3";
string elem4 = "#elem4";
List<string> parameters = new List<string>{ elem1, elem2, elem3, elem4 };
string sql = string.Format(" SELECT * FROM general WHERE element IN ({0})", string.Join(',', parameters.ToArray()));
using(MySqlConnection con = new MySqlConnection("host=localhost;user=mate;password=1234;database=element_database"))
{
con.Open();
MySqlCommand cmd = new MySqlCommand(sql, con);
cmd.Parameters.AddWithValue(elem1, textBox1.Text);
cmd.Parameters.AddWithValue(elem2, textBox2.Text);
cmd.Parameters.AddWithValue(elem3, textBox3.Text);
cmd.Parameters.AddWithValue(elem4, textBox4.Text);
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
string message = reader["element"] as string;
if(!string.IsNullOrEmpty(message))
{
MessageBox.Show(message);
}
}
}
Related
I have a table TümEnvanter$ which has 2 columns equipment code (Ekipman) and their description (Tanım).
User chooses the equipment from the combo box, and I want the description of the chosen equipment to appear in the label at the time they choose from combobox.
Here is what I tried:
SqlCommand cmdTanim = new SqlCommand("select Tanım from TümEnvanter$ where Ekipman = '" + comboBox_ekipman.Text + "'", connect);
connect.Open();
SqlDataReader reader = cmdTanim.ExecuteReader();
string tanim = reader.ToString();
labelTanim.Text = "Ekipman Tanımı: "+tanim+" ";
When I use this code, I get in the label:
Ekipman Tanımı: System.Data.SqlClient.SqlDataReader
How can I fix this? Thank you.
If you only expect a single value, then ExecuteScalar is much simpler than using a reader, i.e.
labelTanim.Text = Convert.ToString(cmdTanim.ExecuteScalar());
In general, perhaps consider tools like "Dapper" which would make this simple even in multi-row cases and solve the SQL injection problem trivially:
string s = connect.QuerySingle<string>(
"select Tanım from TümEnvanter$ where Ekipman = #val", // command
new { val = comboBox_ekipman.Text }); // parameters
You should try this code, it gathers some good practices, such as:
1) Uses using statement to release unamnaged resources (SQL connections, IDisposables in general).
2) Prevents from SQL injection using Parameters field of SqlCommand object.
Also, I used ExecuteScalar method, mentioned by #MarcGravell, which simplifies the code.
public void SqlConn()
{
string tanim = null;
using (SqlConnection connect = new SqlConnection("connectionString"))
{
using (SqlCommand cmdTanim = new SqlCommand())
{
cmdTanim.Connection = connect;
cmdTanim.CommandText = "select Tanım from TümEnvanter$ where Ekipman = #param";
cmdTanim.Parameters.Add("#param", SqlDbType.VarChar).Value = comboBox_ekipman.Text;
connect.Open();
tanim = (string)cmdTanim.ExecuteScalar();
}
}
labelTanim.Text = "Ekipman Tanımı: " + tanim + " ";
}
Something like this:
// wrap IDisposable into using
using (SqlConnection connect = new SqlConnection("Put_Connection_String_Here"))
{
connect.Open();
// Make SQL readable and parametrized
string sql =
#"select Tanım
from TümEnvanter$
where Ekipman = #prm_Ekipman";
// wrap IDisposable into using
using (SqlCommand cmdTanim = new SqlCommand(sql, connect))
{
//TODO: explicit typing Add(..., DbType...) is a better choice then AddWithValue
cmdTanim.Parameters.AddWithValue("#prm_Ekipman", comboBox_ekipman.Text);
// We want one record only; ExecuteScalar() instead of ExecuteReader()
// String interpolation shortens the code
labelTanim.Text = $"Ekipman Tanımı: {cmdTanim.ExecuteScalar()} ";
}
}
Use this code instead by using the reader() method of SqlDataReader to read and access the contents of the SqlDataReader.
SqlCommand cmdTanim = new SqlCommand("select Tanım from TümEnvanter$ where Ekipman = '" + comboBox_ekipman.Text + "'", connect);
connect.Open();
SqlDataReader reader = cmdTanim.ExecuteReader();
if(reader.HasRows){
reader.read();
string tanim = reader.ToString();
labelTanim.Text = "Ekipman Tanımı: "+tanim+" ";
}
Hope this code snippet works for you.
Use below code :
SqlCommand cmdTanim = new SqlCommand("select Tanım from TümEnvanter$ where Ekipman = '" + comboBox_ekipman.Text + "'", connect);
connect.Open();
SqlDataReader reader = cmdTanim.ExecuteReader();
string tanim = string.Empty;
while (reader.Read())
{
tanim= reader["Tanım"].ToString()
}
labelTanim.Text = "Ekipman Tanımı: "+tanim+" ";
I am developing a windows app using mysql and c#. In my app there's a signin page having a sign in button. When i press sign in button it do not loads the values from database and gives me the following error:
Invalid attempt to access a field before calling Read().
Visual Studio indicates the my following code as error:
connection.Open();
string query2 = "SELECT * FROM newregistration where ID='" + id+"'";
MySql.Data.MySqlClient.MySqlCommand myCommand2 = new MySql.Data.MySqlClient.MySqlCommand(query2, connection);
// First Name Reader
MySqlDataReader fnamereader = myCommand2.ExecuteReader();
fnamereader.Read();
Fname = fnamereader.GetString(fnamereader.GetOrdinal("FirstName"));
fnamereader.Close();
// Second Name Reader
MySqlDataReader snamereader = myCommand2.ExecuteReader();
snamereader.Read();
Sname = snamereader.GetString(snamereader.GetOrdinal("SecondName"));
snamereader.Close();
// EMAIL ID Reader
MySqlDataReader emailreader = myCommand2.ExecuteReader();
emailreader.Read();
EmailID = emailreader.GetString(emailreader.GetOrdinal("EmailID"));
emailreader.Close();
DataSet ds = new DataSet();
MyAdapter.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
profile windwo = new profile(this.id, this.Fname,this.Sname,this.EmailID);
AddUserProfileInformation win = new AddUserProfileInformation(this.id);
this.Hide();
windwo.Show();
}
else
{
MessageBox.Show("Sorry Wrong information entered.");
}
connection.Close();
Please help me in sorting out the problem as I am new to development.
You don't need to use a seperate MySqlDataReader every column of your sql query. Just use one MySqlDataReader and read all column values in it.
Looks like, you just need to use something like;
if(fnamereader.Read())
{
Fname = fnamereader.GetString(fnamereader.GetOrdinal("FirstName"));
Sname = fnamereader.GetString(fnamereader.GetOrdinal("SecondName"));
EmailID = fnamereader.GetString(fnamereader.GetOrdinal("EmailID"));
}
But more important, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
string query2 = "SELECT * FROM newregistration where ID=#id";
MySqlCommand myCommand2 = new MySqlCommand(query2, connection);
myCommand2.Parameters.AddWithValue("#id", id);
You don't need to keep executing the datareader before each field
MySqlDataReader reader = myCommand2.ExecuteReader();
reader.Read();
Fname = reader.GetString(reader.GetOrdinal("FirstName"));
Sname = reader.GetString(reader.GetOrdinal("SecondName"));
EmailID = reader.GetString(reader.GetOrdinal("EmailID"));
reader.Close();
A couple of other things
Please use parameterised sql for binding variables - don't just concatenate the variable into sql text - this has security and performance benefits.
You should check the boolean result of the reader.Read() before using it
I think I'm making a fairly amateur mistake somewhere here, but I can't get SQL Parameters to reliably work in C#. Consider the following code:
protected string[] Query(string dataToFind, string tableName, string fieldToCheck, string fieldToReturn)
{
SqlConnection connection = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]);
SqlDataReader dataReader = null;
SqlCommand command = connection.CreateCommand();
command.CommandText = "SELECT " + fieldToReturn + " FROM " + tableName + " WHERE " + fieldToCheck " = '" + dataToFind "'";
try
{
connection.Open();
dataReader = command.ExecuteReader();
etc...
This executes as you would expect, returning the fieldToReturn from the table tableName. However, I understand that this is vulnerably to SQL injections, and that the correct way to avoid this is to use parameters. So I change my code to the following:
protected string[] Query(string dataToFind, string tableName, string fieldToCheck, string fieldToReturn)
{
SqlConnection connection = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]);
SqlParameter[] parameters = new SqlParameter[4];
parameters[0] = new SqlParameter("#dataToFind", dataToFind);
parameters[1] = new SqlParameter("#name", tableName);
parameters[2] = new SqlParameter("#fieldToCheck", fieldToCheck);
parameters[3] = new SqlParameter("#fieldToReturn", fieldToReturn);
SqlDataReader dataReader = null;
SqlCommand command = connection.CreateCommand();
command.Parameters.AddRange(parameters);
command.CommandText = "SELECT #fieldToReturn FROM #tableName WHERE #fieldToCheck = #dataToReturn";
try
{
connection.Open();
dataReader = command.ExecuteReader();
etc...
If I have 3 matches in my database, the first code example returns 3 matches. The second code returns 0 results?!
Am I being stupid and missing something obvious?
Your parameters are:
#dataToFind
#name
#fieldToCheck
#fieldToReturn
Your Query's CommandText has:
#fieldToReturn
#tableName
#fieldToCheck
#dataToReturn
These do not match. They must match in order to be properly applied.
i m trying to retrieve the Specialization ID from a table called Specializationtbl, using C# MSVS 2008 and the table includes SpecializationName and SpecializationID beside some other rows and my question is related to some error " No Data to present ", the command goes as bellow:
SqlCommand READSpecID = new SqlCommand("SELECT * FROM Specializationtbl WHERE SpecializationName='" + comboBox1.Text + "'" , DBcnction);
DBcnction.Open();
SqlDataReader ReadSpecID_ = READSpecID.ExecuteReader();
ReadSpecID_.Read();
int SpecID_ = Convert.ToInt16(ReadSpecID_["SpecID"].ToString());
DBcnction.Close();
i also tried to Select the "SpecID" instead of all the rows, but cant seem to seal the query correctly and keep receiving "No data present " error, any idea where am i making the mistake?
1) Try opening DBcnction before assigning the value to READSPecID
DBcnction.Open();
SqlCommand READSpecID = new SqlCommand("SELECT * FROM Specializationtbl WHERE SpecializationName='" + comboBox1.Text + "'" , DBcnction);
2) Run the command in SSMS:
SELECT * FROM Specializationtbl WHERE SpecializationName ='yourvalue'
and see if any results are returned
3) Check comboBox1.Text has a value in it
4) Validate the contents of comboBox1.Text (Or use paremetrised queries or a stored procedure) to ensure you do not become a victim of SQL Injection: http://en.wikipedia.org/wiki/SQL_injection
Refactor to solve your TWO problems:
Your SQL injection problem when building your SQL statement.
Use ExecuteScalar if you only need one value.
Implement using blocks.
string retVal;
using (var conn = new SqlConnection(SomeConnectionString))
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT SpecID FROM Specializationtbl WHERE SpecializationName= #Name";
cmd.Parameters.AddWithValue("#Name", comboBox1.Text);
conn.Open();
retVal = cmd.ExecuteScalar().ToString();
}
int specID = int.Parse(retVal);
If you really needed more than one value from your statement:
using (var conn = new SqlConnection(SomeConnectionString))
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT SpecID, Value2 FROM Specializationtbl WHERE SpecializationName= #Name";
cmd.Parameters.AddWithValue("#Name", comboBox1.Text);
conn.Open();
var dr = cmd.ExecuteReader();
while (dr.Read())
{
Customer c = new Customer {
ID = dr["SpecID"].ToString(),
Value = dr["Value2"].ToString(),
};
}
}
Need to first test if there are any rows. I suspect the query is returning zero rows.
if (ReadSpecID_.HasRows)
{
ReadSpecID_.Read();
}
I need to execute the following command and pass the result to a label. I don't know how can i do it using Reader. Someone can give me a hand?
String sql = "SELECT * FROM learer WHERE learer.id = " + index;
SqlCommand cmd = new SqlCommand(sql,conn);
learerLabel.Text = (String) cmd.ExecuteReader();
As you can see i create the SQL statement and i execute it, but it does not work. Why?
The console says:
Cannot implicitly SqlDataReader to
String...
How can i get the desired results as String so the label can display it properly.
using (var conn = new SqlConnection(SomeConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT * FROM learer WHERE id = #id";
cmd.Parameters.AddWithValue("#id", index);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
learerLabel.Text = reader.GetString(reader.GetOrdinal("somecolumn"))
}
}
}
It is not recommended to use DataReader and Command.ExecuteReader to get just one value from the database. Instead, you should use Command.ExecuteScalar as following:
String sql = "SELECT ColumnNumber FROM learer WHERE learer.id = " + index;
SqlCommand cmd = new SqlCommand(sql,conn);
learerLabel.Text = (String) cmd.ExecuteScalar();
Here is more information about Connecting to database and managing data.
ExecuteScalar() is what you need here
Duplicate question which basically says use ExecuteScalar() instead.