SQLCommand and SqlDataReader error - c#

Invalid attempt to read when no data is present.
This error occurs on this line
string ingredientName = reader2.GetString(0);
My code:
var ingredientList = new List<Ingredient>();
SqlCommand staffCommand = new SqlCommand();
string conString = EventsUnlimited.Properties.Settings.Default.DatabaseEventsUnlimitedConnectionString;
using (SqlConnection connection = new SqlConnection(conString))
{
connection.Open();
using (SqlCommand command = new SqlCommand("SELECT IngredientID, Quantity FROM CourseIngredients WHERE CourseID =" + courseID, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Obtains the columns from customer
int ingredientID = reader.GetInt32(0);
decimal quantity = reader.GetDecimal(1);
string ingredientNameConstruct;
SqlCommand ingredientCommand = new SqlCommand();
string conString2 = EventsUnlimited.Properties.Settings.Default.DatabaseEventsUnlimitedConnectionString;
using (SqlConnection connection2 = new SqlConnection(conString2))
{
connection2.Open();
using (SqlCommand command2 = new SqlCommand ("SELECT IngredientName FROM Stock WHERE IngredientID =" + ingredientID, connection2))
{
using (SqlDataReader reader2 = command2.ExecuteReader())
{
string ingredientName = reader2.GetString(0);
ingredientNameConstruct = ingredientName;
}
}
}
ingredientList.Add(new Ingredient(courseID, ingredientNameConstruct, ingredientID, quantity));
}
}
}
return ingredientList;
}
I am not sure as to what is causing this issue. There is data in the table and the row I am trying to read from.

You are not calling Read() method for your reader2 object which actually reads a row against the result returned, add that before actually reading column values:
using (SqlDataReader reader2 = command2.ExecuteReader())
{
if(reader2.Read()) // this is needed
{
string ingredientName = reader2.GetString(0);
ingredientNameConstruct = ingredientName;
}
}
if you are expecting multiple rows then use while loop, and if it is always a single row to be expecting as result them you can use reader2.ExecuteScalar too as #bradbury9 mentioned in the comment:
string ingredientName = command2.ExecuteScalar()?.ToString();
ingredientNameConstruct = ingredientName;

Call DataReader.Read Method in your reader2 DataReader to get the results.

Related

Problem with query string and extract values

I can't extract the values through a query and insert them into textboxes
Where am I going wrong?
Request.QueryString.Get("ID_Persona");
string query = "SELECT ID,Nome,Cognome,Email,CodiceFiscale FROM Persona WHERE ID = #id";
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.AddWithValue("#ID","");
cmd.Parameters.AddWithValue("#Nome", TextBox1.Text);
cmd.Parameters.AddWithValue("#Cognome", TextBox15.Text);
cmd.Parameters.AddWithValue("#Email", TextBox20.Text);
cmd.Parameters.AddWithValue("#CodiceFiscale", TextBox22.Text);
con.Open();
cmd.ExecuteNonQuery();
}
You need to use ExecuteReader to read values, something like this:
var connectionString = ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
string query = "SELECT ID,Nome,Cognome,Email,CodiceFiscale FROM Persona WHERE ID = #id";
using (SqlConnection con = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand(query, con))
{
cmd.Parameters.AddWithValue("#ID", Request.QueryString.Get("ID_Persona"));
con.Open();
using (var rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
//IDTextBox? = rdr["Id"].ToString(),
TextBox1.Text = rdr["Nome"].ToString(),
TextBox15.Text = rdr["Cognome"].ToString(),
TextBox20.Text= rdr["Email"].ToString(),
TextBox22.Text= rdr["CodiceFiscale"].ToString(),
}
}
}
}
You should use a ExecuteReader() instead of ExecuteNonQuery() since ExecuteNonQuery is meant for DML operations. Again, you need only the ID value to be passed then why you are passing unnecessary parameters to your query. Remove them all. An example below
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(String.Format("{0}", reader["Email"]));
}
I can see several issues:
You should use ExecuteReader() instead of ExecuteNonQuery()
You should provide just 1 parameter - #ID; I doubt if it should have an empty value.
You should wrap IDisposable into using
Code:
string query =
#"SELECT ID,
Nome,
Cognome,
Email,
CodiceFiscale
FROM Persona
WHERE ID = #id";
using (SqlConnection con = new SqlConnection(...))
{
con.Open();
using SqlCommand cmd = new SqlCommand(query, con)
{
// I doubt if you want empty Id here.
// I've assumed you want to pass ID_Persona
cmd.Parameters.AddWithValue("#ID", Request.QueryString.Get("ID_Persona"));
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
TextBox1.Text = Convert.ToString(reader["Nome"]);
TextBox15.Text = Convert.ToString(reader["Cognome"]);
TextBox20.Text = Convert.ToString(reader["Email"]);
TextBox22.Text = Convert.ToString(reader["CodiceFiscale"]);
}
}
}
}

How to make an "if" based on value retrieved from Query?

I need to insert into a table "pass" or "fail", if from the query done there is a single fail instead of 'RProva' I have to put "fail" if the query can't find a single fail instead of 'RProva' I have to insert "pass", the query is working but I can't figure out how to do the if with the results of a query, maybe I have to use a "for"? Don't know. It is the attempt to make it, the second is the query where I have to insert the result of the possbile "IF"
1.
SqlCommand cmdRD = new SqlCommand("SELECT ResItem AS RD FROM tSE JOIN tL ON tSE.idSE=tL.idL WHERE tL.Selection=1");
var RD = cmdRD.ExecuteScalar();
var values = new List<string>();
using (cmdRD,sqliteCon)
{
using (SqlDataReader reader = cmdRD.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0].ToString());
}
}
}
2.
SqlCommand cmd1 = new SqlCommand("INSERT INTO tSD(NomeItem,ResItemDet,DateStartDet,DateEndDet) OUTPUT inserted.Id VALUES (#NI,#RProva,#DATESE,#DATEED)");
cmd1.Parameters.AddWithValue("#DATESE", DATESE);
cmd1.Parameters.AddWithValue("#DATEED", DATEED);
cmd1.Parameters.AddWithValue("#NI", NI);
using (cmd1,sqliteCon)
{
foreach (var value in values)
{
if (value.Equals(pass))
{
cmd1.Parameters.AddWithValue("#RProva", value);
}
else
{
cmd1.Parameters.AddWithValue("#RProva", fail);
}
cmd1.ExecuteNonQuery();
}
}
int generatedId = Convert.ToInt32(cmd1.ExecuteScalar());
cmd1.Parameters.Clear();
SqlCommand cmd2 = new SqlCommand("UPDATE tSE SET FK_TSD_id = #tsdId FROM tL JOIN tSE ON tL.idL = tSE.idSE WHERE tL.Selection=1 ", sqliteCon);
cmd2.Parameters.AddWithValue("#tsdId", generatedId);
cmd2.ExecuteNonQuery();
MessageBox.Show("Dato Aggiunto");
}
sqliteCon.Close();
1.1
SqlCommand cmdRD = new SqlCommand("SELECT ResItem AS RD FROM tSE JOIN tL ON tSE.idSE=tL.idL WHERE tL.Selection=1", sqliteCon);
var RD = cmdRD.ExecuteScalar();
var tot =pass;
using (cmdRD)
{
using (SqlDataReader reader = cmdRD.ExecuteReader())
{
while (reader.Read())
{
if(reader[0].ToString()==fail)
{
tot = fail;
break;
}
}
MessageBox.Show(tot);
}
}
i'm arrived to that(1.1) it works but i've to insert the TOT into RProva
Based on your question and comment I think you misunderstood ExecuteScalar:
ExecuteScalar executes the query, and returns the first column of the first row in the result set returned by the query. learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.executescalar
I dont know the Type of "RD" or "PASS", but the IF in your example (when using ExecuteScalar) seems OK. Else when you are using ExecuteReader you should use some kind of an loop to iterate through the Items. Like this:
string pass = "abc"; // guessing types and values
string fail = "failed";
string sqliteCon = "Data Source=(localdb)\\MSSQLLocalDB;Database=BooksDb";
using (SqlConnection connection = new SqlConnection(sqliteCon))
{
connection.Open();
var queryString = #"SELECT ResItem AS RD
FROM tSE
JOIN tL ON tSE.idSE = tL.idL
WHERE tL.Selection=1";
var values = new List<string>();
using (SqlCommand command = new SqlCommand(queryString, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0].ToString());
}
}
}
var queryInsert = #"INSERT INTO tSD (NomeItem,ResItemDet,DateStartDet,DateEndDet)
VALUES (#NI, #RProva, #DATESE, #DATEED)";
using (SqlCommand command2 = new SqlCommand(queryInsert, connection))
{
foreach(var value in values)
{
command2.Parameters.Clear();
if (value.Equals(pass))
{
command2.Parameters.AddWithValue("#RProva", value);
}
else
{
command2.Parameters.AddWithValue("#RProva", fail);
}
command2.ExecuteNonQuery();
}
}
}
Theres for sure a better way, but maybe this helps you out.
EDIT:
Here is how I would implement your code example:
using (SqlConnection sqliteCon = new SqlConnection(connection))
{
sqliteCon.Open();
var values = new List<string>();
var query = "SELECT ResItem AS RD FROM tSE JOIN tL ON tSE.idSE=tL.idL WHERE tL.Selection=1";
using (SqlCommand cmdRD = new SqlCommand(query, sqliteCon))
{
var RD = cmdRD.ExecuteScalar();
using (SqlDataReader reader = cmdRD.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0].ToString());
}
}
}
int generatedId = 0;
var query2 = "INSERT INTO tSD(NomeItem,ResItemDet,DateStartDet,DateEndDet) OUTPUT inserted.Id VALUES (#NI,#RProva,#DATESE,#DATEED)";
using (SqlCommand cmd1 = new SqlCommand(query2, sqliteCon))
{
foreach (var value in values)
{
cmd1.Parameters.Clear();
cmd1.Parameters.AddWithValue("#DATESE", DATESE);
cmd1.Parameters.AddWithValue("#DATEED", DATEED);
cmd1.Parameters.AddWithValue("#NI", NI);
if (value.Equals(pass))
{
cmd1.Parameters.AddWithValue("#RProva", value);
}
else
{
cmd1.Parameters.AddWithValue("#RProva", fail);
}
cmd1.ExecuteNonQuery();
}
generatedId = Convert.ToInt32(cmd1.ExecuteScalar());
}
var query3 = "UPDATE tSE SET FK_TSD_id = #tsdId FROM tL JOIN tSE ON tL.idL = tSE.idSE WHERE tL.Selection=1 ";
using (SqlCommand cmd2 = new SqlCommand(query3, sqliteCon))
{
cmd2.Parameters.AddWithValue("#tsdId", generatedId);
cmd2.ExecuteNonQuery();
}
}

get common id numbers from sqldatabase table c#

I need to know how to get all the clientID that are #2 so i could get the programs they are assigned to...so far my code only gets the first clientID with #2 in it...
int progs;
string Command = #"select * from clientprogram where clientProgClientID = #clientID;";
using (MySqlConnection mConnection = new MySqlConnection(mycon))
{
mConnection.Open();
using (MySqlCommand cmd2 = new MySqlCommand(Command, mConnection))
{
cmd2.Parameters.Add(new MySqlParameter("#clientID", lblcID.Text));
using (MySqlDataReader reader = cmd2.ExecuteReader())
{
if (reader.Read())
{
progs = (int)reader["clientProgramID"];
cmbProgram.Items.Add(progs);
}
}
}
mConnection.Close();
}
Change
if (reader.Read())
to
while (reader.Read())
It seems it should be in a loop to add records recursively rather than just the first one
of course it only get the first result because you are reading it only once.
use while(reader.Read()) instead of if(reader.Read()).
while(reader.Read())
{
progs = (int)reader["clientProgramID"];
cmbProgram.Items.Add(progs);
}
change
if (reader.Read())
to
while(reader.Read())
side note; don't use select * when you only need single column data, use select Coumnname from yourtable
int progs;
string Command = #"select * from clientprogram where clientProgClientID = #clientID;";
using (MySqlConnection mConnection = new MySqlConnection(mycon))
{
mConnection.Open();
using (MySqlCommand cmd2 = new MySqlCommand(Command, mConnection))
{
cmd2.Parameters.Add(new MySqlParameter("#clientID", lblcID.Text));
using (MySqlDataReader reader = cmd2.ExecuteReader())
{
while (reader.Read()) // CHANGE TO THIS
{
progs = (int)reader["clientProgramID"];
cmbProgram.Items.Add(progs);
}
}
}
mConnection.Close();
}

How to generate List<String> from SQL query?

If I have a DbCommand defined to execute something like:
SELECT Column1 FROM Table1
What is the best way to generate a List<String> of the returned records?
No Linq etc. as I am using VS2005.
I think this is what you're looking for.
List<String> columnData = new List<String>();
using(SqlConnection connection = new SqlConnection("conn_string"))
{
connection.Open();
string query = "SELECT Column1 FROM Table1";
using(SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
columnData.Add(reader.GetString(0));
}
}
}
}
Not tested, but this should work fine.
Loop through the Items and Add to the Collection. You can use the Add method
List<string>items=new List<string>();
using (var con= new SqlConnection("yourConnectionStringHere")
{
string qry="SELECT Column1 FROM Table1";
var cmd= new SqlCommand(qry, con);
cmd.CommandType = CommandType.Text;
con.Open();
using (SqlDataReader objReader = cmd.ExecuteReader())
{
if (objReader.HasRows)
{
while (objReader.Read())
{
//I would also check for DB.Null here before reading the value.
string item= objReader.GetString(objReader.GetOrdinal("Column1"));
items.Add(item);
}
}
}
}
Or a nested List (okay, the OP was for a single column and this is for multiple columns..):
//Base list is a list of fields, ie a data record
//Enclosing list is then a list of those records, ie the Result set
List<List<String>> ResultSet = new List<List<String>>();
using (SqlConnection connection =
new SqlConnection(connectionString))
{
// Create the Command and Parameter objects.
SqlCommand command = new SqlCommand(qString, connection);
// Create and execute the DataReader..
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
var rec = new List<string>();
for (int i = 0; i <= reader.FieldCount-1; i++) //The mathematical formula for reading the next fields must be <=
{
rec.Add(reader.GetString(i));
}
ResultSet.Add(rec);
}
}
If you would like to query all columns
List<Users> list_users = new List<Users>();
MySqlConnection cn = new MySqlConnection("connection");
MySqlCommand cm = new MySqlCommand("select * from users",cn);
try
{
cn.Open();
MySqlDataReader dr = cm.ExecuteReader();
while (dr.Read())
{
list_users.Add(new Users(dr));
}
}
catch { /* error */ }
finally { cn.Close(); }
The User's constructor would do all the "dr.GetString(i)"
Where the data returned is a string; you could cast to a different data type:
(from DataRow row in dataTable.Rows select row["columnName"].ToString()).ToList();
This version has the same purpose of #Dave Martin but it's cleaner, getting all column, and easy to manipulate the data if you wan't to put it on Email, View, etc.
List<string> ResultSet = new List<string>();
using (SqlConnection connection = DBUtils.GetDBConnection())
{
connection.Open();
string query = "SELECT * FROM DATABASE";
using (SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
var rec = new List<string>();
for (int i = 0; i <= reader.FieldCount - 1; i++)
{
rec.Add(reader.GetString(i));
}
string combined = string.Join("|", rec);
ResultSet.Add(combined);
}
}
}
}

How to Execute T-SQL from c#?

Can anybody give an example for executing a T-SQL statement using C#?
Do you mean something like this:
private static void ReadOrderData(string connectionString)
{
string commandText = "SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(commandText, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
}
}
}
}
Or, perhaps something like:
static public int AddProductCategory(string newName, string connString)
{
Int32 newProdID = 0;
string sql =
"INSERT INTO Production.ProductCategory (Name) VALUES (#Name); "
+ "SELECT CAST(scope_identity() AS int)";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#Name", SqlDbType.VarChar);
cmd.Parameters["#Name"].Value = newName;
try
{
conn.Open();
newProdID = (Int32)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return (int)newProdID;
}
Source: MSDN
I suggest that you start with an ADO.NET turorial like this one
http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson01.aspx
How to use SQLCommand
http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson03.aspx
Using a reader:
SqlConnection MSSQLConn = new SqlConnection("your connection string");
MSSQLConn.Open();
SqlCommand MSSQLSelectConsignment = new SqlCommand();
MSSQLSelectConsignment.CommandText = "select * from yourtable where blah = #blah";
MSSQLSelectConsignment.Parameters.AddWithValue("#blah", somestring);
MSSQLSelectConsignment.Connection = MSSQLConnOLD;
SqlDataReader reader = MSSQLSelectConsignment.ExecuteReader();
while (reader.Read())
{
...
}
To bring back a single value:
MSSQLSelectConsignment.CommandText = "select fieldname from yourtable where blah = #blah";
string yourstring = MSSQLSelectConsignment.ExecuteScalar().ToString();
or to bring back number of rows affected for updates etc:
MSSQLSelectConsignment.CommandText = "update yourtable set yourfield = 0 where blah = #blah";
int yourint = MSSQLSelectConsignment.ExecuteNonQuery();
Hope helps :)

Categories

Resources