Invalid attempt to call Read when reader is closed C# - c#

I am opening a data reader within another one, but when I open the second data reader and try to read the data, it says that it is closed even though I just opened it.
Here is my function:
protected void checkBookStockAgain()
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionStore"].ConnectionString);
conn.Open();
string selectCartString = "Select Item, Price, Quantity From ShoppingCart Where Username = #User";
SqlCommand cmd = new SqlCommand(selectCartString, conn);
cmd.Parameters.AddWithValue("#User", Session["user"].ToString());
SqlDataReader readCart = cmd.ExecuteReader();
while (readCart.Read())
{
string selectBookInfo = "Select Quantity from BookInfo where Title = #Title";
SqlCommand bookInfoQuantitycmd = new SqlCommand(selectBookInfo, conn);
bookInfoQuantitycmd.Parameters.AddWithValue("#Title", readCart["Item"]);
SqlDataReader quantityReader = bookInfoQuantitycmd.ExecuteReader();
while (quantityReader.Read())
{
if (Convert.ToInt32(readCart["Quantity"]) > Convert.ToInt32(quantityReader["Quantity"]))
{
updateCart = false;
quantityReader.Close();
readCart.Close();
conn.Close();
}
else if (Convert.ToInt32(readCart["Quantity"]) < Convert.ToInt32(quantityReader["Quantity"]))
{
updateCart = true;
invQuantity = Convert.ToInt32(quantityReader["Quantity"].ToString()) - Convert.ToInt32(readCart["Quantity"].ToString());
quantityReader.Close();
readCart.Close();
conn.Close();
}
else if (Convert.ToInt32(readCart["Quantity"]) == Convert.ToInt32(quantityReader["Quantity"]))
{
updateCart = true;
removeBookFromStore(readCart);
quantityReader.Close();
readCart.Close();
conn.Close();
}
else
{
quantityReader.Close();
readCart.Close();
conn.Close();
}
}
}
}
The error given states "Invalid attempt to call Read when reader is closed" and the error occurs when trying to run the while loop through quantityReader. As a side note, I've enabled MARS (Multiple Active Results Sets) in my connection string.

Related

Access attributes from the database

In this database table (administration), there are 4 attributes (email, name, password and mobile phone). I need that inside the if I can use each one of them but I don't know how I can access them.
How can I do this?
private void button_login_Click(object sender, EventArgs e)
{
String username, user_password;
username = txt_username.Text;
user_password = txt_password.Text;
try
{
String query = "SELECT * FROM administracao WHERE email = '"+txt_username.Text+"' AND password = '"+txt_password.Text+"'";
SqlDataAdapter sda = new SqlDataAdapter(query, conn);
DataTable dtable = new DataTable();
sda.Fill(dtable);
if (dtable.Rows.Count > 0)
{
// username = txt_username.Text;
// user_password = txt_password.Text;
/* Menuform form2 = new Menuform();
form2.Show();
this.Hide();*/
}
else
{
MessageBox.Show("Invalid Login details", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
txt_username.Clear();
txt_password.Clear();
txt_username.Focus();
}
}
catch
{
MessageBox.Show("Error");
}
finally
{
conn.Close();
}
}
For communication with database I would strongly recommend Entity Framework.
In your case you can use SqlDataReader to get output data from sql query
Code Example:
public void GetData()
{
var query = "your query";
var connectionString = "your connection string";
using (var connection = new SqlConnection(connectionString))
{
var command = new SqlCommand(query, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
// Iterate all selected rows
while (reader.Read())
{
int value1 = (int)reader["Int column name"];
string value2 = (string)reader["String column name"];
}
}
finally
{
reader.Close();
}
}
}
NOTE:
In real project NEVER store passwords as plaintext. How to do it properly
As people already mentioned in the comments, when you decide to execute query directly from the code NEVER combine query like you did, because of SQL Injection. Use parametrized SqlCommands. How to do it

How to get data in INT from SQLDataReader in .NET

I am trying to get int value from the database but It is throwing an error
Unable to cast object of type 'System.Byte' to type 'System.Int32'.
In the database, Active field is tinyint.
Also, how to return both values from this method.
private string CheckData(string firstValue, string SecondValue, int Active)
{
string Data = "";
StringBuilder sb = new StringBuilder();
string query = #"select M.ident Mi, mmp.active Active
from Iden.Iden M
inner join PtM.MPt MMP on MMP.mPat = M.id
where M.ident = 'firstValue'
and Mi.ident = 'SecondValue'";
sb.Append(query);
sb.Replace("firstValue", firstValue);
sb.Replace("SecondValue", SecondValue);
SqlConnection connection = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(sb.ToString());
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.Text;
cmd.Connection = connection;
try
{
connection.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Data = reader.GetString(reader.GetOrdinal("Mi"));
Active = reader.GetInt32(reader.GetOrdinal("Active"));
}
}
}
catch (Exception ex)
{
_log.Error($"Exception:{ex.Message}");
}
finally
{
connection.Close();
connection.Dispose();
}
return Data;
}
Here's a stab at it. I can't debug it (since I don't feel like creating a database).
First I create a type to hold the results. You could just use a Tuple, but this seems clearer:
public class DataActive
{
public string Data { get; set; }
public byte Active { get; set; }
}
I make your function return a collection of these - it's not obvious from your code that there is only one.
You'll also notice that I use SqlParameters to add firstValue and secondValue to your query. Look up SQL Injection (and Little Bobby Tables).
If you are using a recent version of C# (which I don't), there's a new syntax for using that requires less indenting. The using statements stick a call to Dispose in a finally statement at the end of the block. Also note that I'm disposing the SqlCommand and the DataReader
public static IEnumerable<DataActive> CheckData(string firstValue, string secondValue)
{
var results = new List<DataActive>();
const string query = #"select M.ident Mi,mmp.active Active from Iden.Iden M
Inner join PtM.MPt MMP on MMP.mPat =M.id
where M.ident = #firstValue and Mi.ident = #secondValue";
using (var connection = new SqlConnection(connString))
{
using (var cmd = new SqlCommand(query))
{
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.Text;
cmd.Connection = connection;
cmd.Parameters.Add("#firstValue", SqlDbType.NVarChar, 50).Value = firstValue;
cmd.Parameters.Add("#secondValue", SqlDbType.NVarChar, 50).Value = secondValue;
try
{
connection.Open();
using (var reader = cmd.ExecuteReader())
{
var dataOrdinal = reader.GetOrdinal("Mi");
var activeOrdinal = reader.GetOrdinal("Active");
if (reader.HasRows)
{
while (reader.Read())
{
results.Add(new DataActive
{
Data = reader.GetString(dataOrdinal),
Active = reader.GetByte(activeOrdinal),
});
}
}
}
}
catch (Exception ex)
{
_log.Error($"Exception:{ex.Message}");
}
}
}
return results;
}
If your TINY_INT Active represents a boolean value, figure out what the rule is, and do a conversion after you get the value using reader.GetByte.
One final note, it's often better to log ex.ToString() rather than ex.Message. You get the message and the stack that way.

How to query specific column in a UWP application?

I need to create a login that displays user data after login in a gridview / datatable
I'm able to display the username / password but not the user ID that's needed.
I've also tried creating a class where the values gets stored after login
private bool DataValidation(string user, string pass)
{
using (MySqlConnection conn = new MySqlConnection(connectionString))
using (MySqlCommand cmd = new MySqlCommand("SELECT * "+
"FROM member " +
"WHERE username=#user AND password=#pass;", conn))
{
cmd.Parameters.AddWithValue("#user", user);
cmd.Parameters.AddWithValue("#pass", pass);
cmd.Connection = conn;
cmd.Connection.Open();
MySqlDataReader login = cmd.ExecuteReader();
List<Connect> connectList = new List<Connect>();
while (login.Read())
{
Connect connect = new Connect();
connect.username = login.GetString(0);
connect.password = login.GetString(1);
connect.userID = login.GetString(4);
connectList.Add(connect);
}
if(connectList.Count > 0)
{
return true;
}
else
{
return false;
}
}
I'm mostly not sure how to store or display the values after they have been queried
Based on our conversation in the comments, let's focus on this code:
MySqlDataReader login = cmd.ExecuteReader();
if (login.Read())
{
conn.Close();
return true;
}
else
{
conn.Close();
return false;
}
The only thing we are doing here is finding out if login contains any rows. But we are not doing anything with those rows.
Let's try something like this instead:
MySqlDataReader login = cmd.ExecuteReader();
while (login.Read())
{
var something1 = login.GetString(0); // this will get the value of the first column
var something2 = login.GetString(1); // this will get the value of the second column
}
Or, if you are adding the results to an object:
MySqlDataReader login = cmd.ExecuteReader();
List<MyObject> myObjectList = new List<MyObject>;
while (login.Read())
{
MyObject myObject = new MyObject;
myObject.something1 = login.GetString(0); // this will get the value of the first column
myObject.something2 = login.GetString(1); // this will get the value of the first column
myObjectList.Add(myObject);
}
if (myObjectList.Count > 0)
{
return true;
}
else
{
return false;
}
You will need to adjust to meet your needs, but hopefully, this will get you there.
More info here: SqlDataReader.Read Method

C# asp.NET displaying output of a query to screen. Error: 'System.ArgumentException' in Oracle.DataAccess.dll

First post here. I'm trying to create a website that fetches data from an Oracle database and returns some tables. I was able to connect my database fine and made a DataConnector that returns a list of CodeDesc objects. My main problem right now is simply displaying that data to the screen, preferably in the form of a drop down list but I'm using a GridView for now.
Here's my front end:
protected void Button1_Click(object sender, EventArgs e)
{
DataConnector dc = new DataConnector();
GridView2.DataSource = dc.getCodeTypes();
GridView2.DataBind();
}
When I click the button, nothing is generated and the debugger only says "Exception thrown: 'System.ArgumentException' in Oracle.DataAccess.dll" Any help would be appreciated. This is my first time doing web development and it's been a struggle to get even this far. I'm using Visual Studio 2015
Back End:
//Create datatable to get info from db & return results
public List<CodeDesc> getCodeTypes()
{
try
{
OracleConnection con = new OracleConnection(connString);
con.Open();
string query = "select id, descr from code_desc where code_type_id = 0";
// Create the OracleCommand
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
// Execute command, create OracleDataReader object
OracleDataReader reader = cmd.ExecuteReader();
List<CodeDesc> L = new List<CodeDesc>();
while (reader.Read())
{
CodeDesc c = new CodeDesc();
c.id = reader.GetInt32(0);
c.description = reader.GetString(1);
L.Add(c);
}
// Clean up
reader.Dispose();
cmd.Dispose();
con.Dispose();
System.Diagnostics.Debug.WriteLine(L);
return L;
}
catch (Exception ex)
{
// catch clause here...
}
}
CodeDesc:
public class CodeDesc
{
public int id { get; set; }
public string description { get; set; }
}
Any help would be great.
You never set the query string to the CommandText property of the OracleCommand. Of course this can only result in an exception when you try to execute your command.
Said that, remember that every disposable object should be enclosed in a using statement. This is very important in case of exceptions because the correct closing and disposing is executed automatically exiting from the using block
public List<CodeDesc> getCodeTypes()
{
try
{
List<CodeDesc> L = new List<CodeDesc>();
string query = "select id, descr from code_desc where code_type_id = 0";
using(OracleConnection con = new OracleConnection(connString))
using(OracleCommand cmd = new OracleCommand(query, con))
{
con.Open();
// Execute command, create OracleDataReader object
using(OracleDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
CodeDesc c = new CodeDesc();
c.id = reader.GetInt32(0);
c.description = reader.GetString(1);
L.Add(c);
}
}
}
System.Diagnostics.Debug.WriteLine(L);
return L;
}

assign data from table to labels using c#

I'm using c# in a ASP.Net web application.I have the following query:
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["chestionar"].ConnectionString);
con.Open();
SqlCommand cmd = new SqlCommand("select * from personal,Intrebari where personal.cod_numeric_personal=#cnp AND Intrebari.id_intrebare=14 AND Intrebari.id_intrebare=15 ", con);
cmd.Parameters.AddWithValue("#cnp", Session["sesiune_cnp"]);
SqlDataReader rdr;
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
lbl1.Text = rdr["Nume"].ToString();
intrebare6.Text = rdr["Intrebari"].ToString();
intrebare7.Text = rdr["Intrebari"].ToString();
}
I want those two values for id_intrebare=14 and 15 to assign it to those 2 labels.How can i refer to those?
In order to read stuff from the reader you need to include it in the select statement for you sql, it is better to select it explicitly rather than use select *.
but you are not currently going to get any results returned because id_intrebare cannot be both 14 and 15
you then need to read id_intreabare ratherr than Intreabari.
Try this, notice the try catch block, I also changed your SQL query.
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["chestionar"].ConnectionString);
string qry="select * from personal,Intrebari where personal.cod_numeric_personal=#cnp AND Intrebari.id_intrebare IN (14,15);
SqlCommand cmd = new SqlCommand(qry, con);
cmd.Parameters.AddWithValue("#cnp", Session["sesiune_cnp"]);
try
{
con.Open();
SqlDataReader rdr= cmd.ExecuteReader();
if(rdr.HasRows)
{
while (rdr.Read())
{
lbl1.Text = rdr["Nume"].ToString();
intrebare6.Text = rdr["Intrebari"].ToString();
intrebare7.Text = rdr["Intrebari"].ToString();
}
}
}
catch(SQLException ex)
{
lblStatus.Text="An error occured"+ex.Message;
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
If you want to assign texts to different numbered lables in a loop, you can refer to the control id with FindControl of the current page
int numeOrdinal = reader.GetOrdinal("Nume");
int intrebariOrdinal = reader.GetOrdinal("Intrebari");
int i = 1;
while (rdr.Read()) {
// Nume (Romanian) = Name
page.FindControl("lbl" + i).Text = reader.IsDBNull(numeOrdinal)
? ""
: rdr.GetString(numeOrdinal);
// Intrebari (Romanian) = Question
page.FindControl("intrebari" + i + 5).Text = reader.IsDBNull(intrebariOrdinal)
? ""
: rdr.GetString(intrebariOrdinal);
i++;
}
Try using cmd.ExecuteScalar it will return the first reuslt it finds so you have to define your conditions well. Also it returns object type so you will have to cast the result

Categories

Resources