How can I find my product_id without using datareader? - c#

My variable names, database tables are right, I get error like this;
MySql.Data.MySqlClient.MySqlException: 'There is already an open DataReader associated with this Connection which must be closed first.'
public string urun_adi_bul(string urun_id)// find product name
{
if (genel.baglanti.State == ConnectionState.Closed)
{
genel.baglanti.Open();
}
string urun_adi = "";
genel.sqlgonder.Connection = genel.baglanti;
genel.sqlgonder.CommandText = "Select * from urunler where urun_id="+urun_id;
MySqlDataReader oku = genel.sqlgonder.ExecuteReader();
while (oku.Read())
{
urun_adi = oku["urun_id"].ToString();
}
oku.Close();
return urun_adi;// product name
}
public void hesapGetir(ListView lvSiparis, string masa_id)
{
genel.baglanti.Open();
MySqlCommand sqlgonder = new MySqlCommand();
sqlgonder.Connection = genel.baglanti;
sqlgonder.CommandText = "Select * from adisyonlar where masa_id = "+masa_id;
MySqlDataReader oku = sqlgonder.ExecuteReader();
lvSiparis.Items.Clear();
string urun_adi = "",urun_id="";
while (oku.Read())
{
urun_id = oku["urun_id"].ToString();
decimal fiyat = Convert.ToDecimal(urun_fiyati_bul(urun_id)); // price
decimal adet = Convert.ToDecimal(oku["urun_adet"]); // piece
decimal toplam = fiyat * adet; // total
urun_adi = urun_adi_bul(urun_id);
ListViewItem item = new ListViewItem(urun_adi);
item.SubItems.Add(adet.ToString());
item.SubItems.Add(toplam.ToString());
lvSiparis.Items.Add(item);
}
oku.Close();
genel.baglanti.Close();
}
How can I use 2 datareaders in a loop?

You can have only one open reader (or any kind of query) per connection. But you actually only need one reader if you combine the two queries with a JOIN:
SELECT adisyonlar.urun_id, urun_adet, urunler.urun_id
FROM adisyonlar
LEFT JOIN urunler
ON adisyonlar.urun_id = urunler.urun_id
This way you let the db do the work to find the matching records, and you only need one query instead of asking the db again and again for every row in adisyonlar.
Note that it's better practice to explicity name the columns you want to fetch instead of fetching all columns with SELECT *.
Plus: your queries are open to SQL injection! Please use parameterized queries.

Related

How to run multiple data readers on single my sql connection

MySqlConnection con = GetConnection();
string sql = "SELECT COUNT(ID) FROM booking WHERE DATE(Booking_Date) = CURDATE()";
string sql2 = "SELECT SUM(Fare) FROM booking WHERE DATE(Booking_Date) = CURDATE()";
MySqlCommand cmd = new MySqlCommand(sql, con);
cmd.CommandType = System.Data.CommandType.Text;
MySqlDataReader BookingToday = cmd.ExecuteReader();
while (BookingToday.Read())
{
label6.Text = BookingToday.GetValue(0).ToString();
}
This is my C# code and I want to run both the given queries to get result at once. But I don't know how to run multiple data readers on single connection or run 2 connections at once. Anyone please help me in this regard
You can use one query:
string sql = "SELECT COUNT(ID), SUM(Fare) FROM booking WHERE DATE(Booking_Date) = CURDATE()";
In this specific case: you don't need to - you can use the code shown in slaakso's answer to perform both aggregates in one query.
In the more general case:
using (var reader = cmd1.ExecuteReader())
{
// while .Read(), etc
}
using (var reader = cmd2.ExecuteReader())
{
// while .Read(), etc
}
i.e. sequentially and not overlapping (unless your provider supports the equivalent of "MARS").
You can also often issue multiple queries (select) in a single command; you use NextResult() to move between them:
using (var reader = cmd.ExecuteReader())
{
// while .Read(), etc, first grid
if (reader.NextResult())
{
// while .Read(), etc, second grid
}
}
You can't open multiple data readers simultaneously from a single connection.
If you want a single result, you can use ExecuteScalar.
var result1 = (DateTime)new MySqlCommand("select now()", con).ExecuteScalar();
Console.WriteLine(result1);
var result2 = (DateTime)new MySqlCommand("select date_add(now(), interval 10 day)", con).ExecuteScalar();
Console.WriteLine(result2);
For multi-row results, you can store them in a DataTable.
var dt1 = new DataTable();
dt1.Load(new MySqlCommand("select id from table1", con).ExecuteReader());
var dt2 = new DataTable();
dt2.Load(new MySqlCommand("select name from table1", con).ExecuteReader());
foreach(var row in dt1.AsEnumerable())
{
Console.WriteLine($"id:{row["id"]}");
}
foreach (var row in dt2.AsEnumerable())
{
Console.WriteLine($"name:{row["name"]}");
}

How to read the column SqlDataReader

I am working on my windows form applications. In this winform, I have a checkListBox which binded the data from my sql db. I am trying to match the checkListBox's checkedItem to my sql table column's text which is stored as a nvarchar data type. I ran the debug mode and found out that it skip the entire while loop when the program is executed. I have no idea why because the valuable name items did actually showed which checkbox in checkListBox is checked
This is my code.
foreach(var items in checkListBox1.CheckedItems){
string query = "select * from my_table WHERE employeeName = '"+items+"'"
SqlCommand myCommand = new SqlCommand(query, myConn);
SqlDataReader dr = myCommand.ExecuteReader();
while(dr.Read()){
//read the column
}
}
Here is the screen Shot. I tried to fetch the chineseName in the column (don't worry about what it is lol)
You have multiple problems in your code. You don't need to write your query in ForEach loop. And if you are expecting to get multiple values from your checklistbox then equalto = operator is not your friend, you would need to use IN operator. Now check below example.
private void button1_Click(object sender, EventArgs e)
{
string items = string.Empty;
foreach (var item in checkedListBox1.CheckedItems)
{
if (items.Length == 0)
items = item.ToString();
else
items = items + "," + item;
}
//make myCommand object and open connection on your own
myCommand = new SqlCommand(query, myConn);
string query = #'select distinct firstName, lastName, chineseName, teacherEmail, entryYear, leaveYear, userLoginId, ad.applicationId
from [teacher_detail] as td
LEFT JOIN[class_detail] as cd ON td.teacherId = cd.teacherId
LEFT JOIN[application_teacher] as at ON at.teacherId = td.teacherId
LEFT JOIN[application_detail] as ad ON at.applicationId = ad.applicationId
Where ad.applicationId = 2
and chineseName in (#name)'
myCommand.Parameters.Add("#name", SqlDbType.nvarchar);
myCommand.Parameters["#name"].Value = items;
//now execute query
}
As Data type in database is nvarchar try it by modifying the following statement in your code
string query = "select * from my_table WHERE employeeName = '"+items+"'"
to
string query = "select * from my_table WHERE employeeName = N'"+items.ToString()+"'"
Prefix 'N' is used for the value to compare from checked item

Combining 2 queries into 1 struct

I have 2 different databases and I need to get results of their queries into 1 structure:
struct my_order
{
public int Id_N
public int OrderId;
public string Discount;
public string CustomerId;
public string ShipAddress;
}
My queries:
my_order ret = new my_order();
SqlConnection con = open_sql(firstDB);
string firstQuery= #" SELECT OrderId, Discount FROM Orders
WHERE Id = " + id_n.ToString(); //some ID that I got earlier
SqlCommand command = new SqlCommand(firstQuery, con);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
ret.Id_N = id_n;
ret.OrderId = reader["OrderId"].ToString();
ret.Discount = reader["Discount"].ToString();
}
SqlConnection second_con = open_sql(secondDB);
string secondQuery= #" SELECT CustomerId, ShipAdress FROM Details
WHERE Id = " + id_n.ToString();
//id_n - some ID that I got earlier(the same as in the first query)
SqlCommand secondCommand = new SqlCommand(secondQuery, second_con);
SqlDataReader secondReader = secondCommand.ExecuteReader();
while (secondReader.Read())
{
ret.Id_N = id_n;
ret.CustomerId = secondReader["CustomerId"].ToString();
ret.ShipAddress = secondReader["ShipAddress"].ToString();
}
The problem is that compiler get the result from the firstQuery and doesn't from the secondQuery. It doesn't get into while(secondReader.Read()).
How to correct it?
PS: I change the code and queries a little bit, because my is too big, but the question is the same.
Regards,
Alexander.
Shooting into the blue here without an error or a more detailed description of what is going wrong, but you have a typo in your code:
string secondQuery= #" SELECT CustomerId, ShipAdress FROM Details WHERE Id = " + id_n.ToString();
ret.ShipAddress= secondReader["ShipAddress"].ToString();
You are writing ShipAdress with one and 2 d's.
Choose the correct version
The reason why it doesn't go into the while (secondReader.Read()) { ... } is because the second query does not return any rows, because there are no rows in table Details with the specified Id value.
you may use the propriete HasRows and IsDBNull(columnIndex) method to check if it contains data
if (secondReader.HasRows)
// Get data
else
//there is no data

display some data from the database to datagridview

command.CommandText = "SELECT * FROM Books WHERE Author='"+Convert.ToString(comboBox1.SelectedItem)+"'";
reader = command.ExecuteReader();
ex.
I select "John" from the comboBox.
the datagridview will show the data from the database whose Author="John".
For example, there are 4 books with the same author(John), how can I display those data to datagridview?
something like
command.CommandText = "SELECT * FROM Books WHERE Author='"+Convert.ToString(comboBox1.SelectedItem)+"'";
var reader = command.ExecuteReader();
var list = new List<string>();
while(reader.Read())
{
list.Add(reader["Author"].ToString())
}
datagridview.DataSource = list;
there are many (many!) things wrong with doing it this way - but it wil properly get you on your way.
First of all - try to avoid having your GUI so "close" to the db code.
Secondly, as mentionsed, this code is vulnerable to SQL injection.
My suggestion:
public List<string> GetAuthors(string aurtherName)
{
using(var con = CreateConnection()//somehow )
{
var command = con.CreateCommand();
string sql = "SELECT * FROM Books WHERE Author='#value'";
command.Parameters.AddWithValue("#value", aurtherName);
command.CommandText = sql ;
var list = new List<string>();
while(reader.Read())
{
list.Add(reader["Author"].ToString())
}
return list;
}
}
that way you can call it like this:
datagridview.DataSource = GetAuthors(comboBox1.SelectedItem);

SQL select from database in C#

I have the following code in C#:
string query = "SELECT * FROM Zboruri WHERE cod_aeroport = " + country;
using (var command = new SqlCommand(query, connection))
{
var list = new ArrayList();
var reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
string data1 = reader.GetString(1);
string data2 = reader.GetString(2);
list.Add(cod_aeroport);
list.Add(data1);
list.Add(data2);
}
}
else
{
string raspuns = "nu este info";
list.Add(raspuns);
}
reader.Close();
connection.Close();
return list;
}
My database table has these columns:
data1(numeric(18,0))
data2(numeric(18,0))
...........
and it giving me error:
Index was outside the bounds of the array.
on this line of code:
string data2 = reader.GetString(2);
How can I fix error?
index starts at 0, not 1
string data1 = reader.GetString(0);
string data2 = reader.GetString(1);
I'll prefer to use the column names retrieve from the table because it gives more description than using index of the column (which is usually the reason for index out of bounds exception)
ex,
string data1 = reader["colName1"].ToString();
string data2 = reader["colName2"].ToString();
side-note: please do use parameters in your query,
string query = "SELECT * FROM Zboruri WHERE cod_aeroport = #country";
and before you call ExecuteReader add this line,
command.Parameters.AddWithValue("#country", country);
var reader = command.ExecuteReader();
The index is zero based, so the first column is 0, the second is 1. You should really use the named version of the columns though;
string data1 = reader["data1"].ToString();
One more thing, you should probably parameterize your query to avoid SQL injection problems, in this case it's almost as simple as your original query and much safer. It also helps the database save quite a bit of time and memory on similar queries;
string query = "SELECT * FROM Zboruri WHERE cod_aeroport = #country";
using (var command = new SqlCommand(query, connection))
{
command.Parameters.AddWithValue("#country", country);
var list = new ArrayList();
...
You should better access them by name, by resolving the index by name using the GetOrdinal() method first, so that the code doesn't break if the query is extended later.
if (reader.HasRows)
{
int data1Index = reader.GetOrdinal("data1");
int data2Index = reader.GetOrdinal("data2");
while (reader.Read())
{
string data1 = reader.GetString(data1index);
string data2 = reader.GetString(data2index);
list.Add(cod_aeroport);
list.Add(data1);
list.Add(data2);
}
}
Note that this is the slightly better approach compared to using the named indexer because it avoids looking up the index on every row.
Also, please do parametrize the query to avoid SQL injection.

Categories

Resources