C# to SQL ExecuteReader() getting stuck - c#

When running the below method in my application the app freezes and when I pause VS it seems to be stuck on the line that goes:
SqlDataReader reader = select.ExecuteReader();
I've got other SQL methods running fine so I know the connection string is correct, I've double checked the SQL and that's fine. Am I wrong in think the reader variable can not contain the returning value of the scalar function when the ExecuteReader() is called?
public static bool AccountValidation(string username, string password)
{
string statement = "select dbo.AccountValidation('" + username + "','" + password + "')";
SqlCommand select = new SqlCommand(statement, connect);
connect.Open();
SqlDataReader reader = select.ExecuteReader();
string result = reader.ToString();
connect.Close();
if (result != "true")
{
return false;
}
else
{
return true;
}
}

The main problem is that you are not actually reading anything back from the data reader, you have to iterate over the result set and then read based on ordinal/positional index.
There are also other big problems like
Not using parameters which leaves the code vulnerable to sql injection attacks.
Not wrapping your disposables in using blocks which could leave database connections open if there are exceptions
sharing db connections in your types. Create connections on an as needed basis and then dispose them when you are done.
Here is your updated code with fixes. I guessed at the column types (varchar), fix that and the lengths as they are implemented in your schema.
public static bool AccountValidation(string username, string password)
{
const string statement = "select dbo.AccountValidation(#username, #password)";
string result = null;
// reference assembly System.Configuration
string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["YourDb"].ConnectionString;
using(var connection = new SqlConnection(connStr))
using(SqlCommand cmd = new SqlCommand(statement, connect))
{
cmd.Parameters.Add(new SqlParameter("#username", SqlDbType.VarChar, 200){Value = username});
cmd.Parameters.Add(new SqlParameter("#password", SqlDbType.VarChar, 200){Value = password});
connect.Open();
using(SqlDataReader reader = cmd.ExecuteReader())
{
if(reader.Read())
result = reader.GetString(0); // read back the first column of the first row
}
}
if (result != "true")
{
return false;
}
else
{
return true;
}
}
On a side note it would be cleaner to return a bit from your database function AccountValidation and then read that back with reader.GetBoolean(0) and assign that to the result and return that directly instead of doing string comparisons.
Also, as mentioned above in the comments, if you are only returning 1 value it is easier (and less code) to call ExecuteScalar instead of ExecuteReader.

Add the line
reader.Read();
before the line
string result = reader.ToString();
Also, please parameterize your queries.

I don't have enough reputation to leave a comment, but to answer part of your question, yes, you can use a SqlDataReader to read single scalar results with or without column aliases.

Related

Check if a row exists using windows form?

I was creating an Appointment Table and i want to check if the row contains same Date,Slot,HR exists before another user enter.
The Connection is Opened Before this shown code.
SqlCommand slot_check = new SqlCommand("select * from Appointment where AppoinmentDate='"+textBox1.Text+"' and Slot='"+comboBox3.Text+ "'and HRName='" +comboBox2.Text+"'");
SqlDataReader Exist = slot_check.ExecuteReader();
if (Exist.HasRows)
{
string message = "Appointment Already Exists!!!!!";
MessageBox.Show(message);
}
else
{
string message = "Update";
MessageBox.Show(message);
}
System.InvalidOperationException: 'ExecuteReader: Connection property has not been initialized.'
To execute a command two informations are essential:
The sql string to execute and the connection to reach the database.
Without the connection your command cannot be executed because the framework doesn't know how to read or write the database.
There is an overload for the SqlCommand constructor that takes the two required parameters:
SqlCommand cmd = new SqlCommand(sqlText, connectionInstance);
So your code should be something like this
// The command text to run, without string concatenations and with parameters placeholders
string sqlText = #"select * from Appointment
where AppoinmentDate=#aptDate
and Slot=#slot
and HRName=#name";
// Using statement to correctly close and dispose the disposable objects
using(SqlConnection cnn = new SqlConnection(connectionString))
using(SqlCommand slot_check = new SqlCommand(sqlText, cnn))
{
// A parameter for each placeholder with the proper datatype
cmd.Parameters.Add("#aptDate", SqlDbType.Date).Value = Convert.ToDateTime(textBox1.Text);
cmd.Parameters.Add("#slot", SqlDbType.NVarChar).Value = comboBox3.Text;
cmd.Parameters.Add("#name", SqlDbType.NVarChar).Value = comboBox2.Text;
cnn.Open();
// Even the SqlDataReader is a disposable object
using(SqlDataReader Exist = slot_check.ExecuteReader())
{
if (Exist.HasRows)
{
string message = "Appointment Already Exists!!!!!";
MessageBox.Show(message + " " + Exist + comboBox2.Text);
}
else
{
string message = "Update";
MessageBox.Show(message);
}
}
}
As you can see the code now has a connection passed to the command constructor and a command text built without concatenating strings but using parameters.
Using parameters is a mandatory approach for any kind of database related operation. Without parameters your code could be exploited with the well known Sql Injection hack, but also, the simple presence of a single quote in your values, could break the sql syntax resulting in a Syntax Error Exception
Note that this code could still be wrong because I don't know what kind of data is stored in your table in the columns used in the WHERE statement. I assumed some kind of type but you should check against your table and verify if they are correct.

How to retrieve data from SQL Server in C# using ADO.NET?

Would you please show me how to retrieve data from SQL Server to C# (Windows Forms application)?
Consider I have a textbox and I need to fill it with data from SQL Server WHERE 'emp_id = something' for example, how can I do it without a DataGridView?
Or take this another example:
SELECT sum(column) FROM table_name
How to get the value of the above command (also without a DataGridView)?
There are multiple ways to achieve this. You can use DataReader or DataSet \ DataTable. These are connected and disconnected architectures respectively. You can also use ExecuteScalar if you want to retrieve just one value.
Recommendations:
Enclose SqlConnection (and any other IDisposable object) in using block. My code uses try-catch block.
Always use parameterized queries.
Following is some example code with DataReader in case your query returns multiple rows. The code is copied from here.
//Declare the SqlDataReader
SqlDataReader rdr = null;
//Create connection
SqlConnection conn = new SqlConnection("Your connection string");
//Create command
SqlCommand cmd = new SqlCommand("Your sql statement", conn);
try
{
//Open the connection
conn.Open();
// 1. get an instance of the SqlDataReader
rdr = cmd.ExecuteReader();
while(rdr.Read())
{
// get the results of each column
string field1 = (string)rdr["YourField1"];
string field2 = (string)rdr["YourField2"];
}
}
finally
{
// 3. close the reader
if(rdr != null)
{
rdr.Close();
}
// close the connection
if(conn != null)
{
conn.Close();
}
}
In case your query returns single value, you can continue with above code except SqlDataReader. Use int count = cmd.ExecuteScalar();. Please note that ExecuteScalar may return null; so you should take additional precautions.
Filling a Textbox:
using (var sqlConnection = new SqlConnection("your_connectionstring"))
{
sqlConnection.Open();
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = "select sum(field) from your_table";
object result = sqlCommand.ExecuteScalar();
textBox1.Text = result == null ? "0" : result.ToString();
}
sqlConnection.Close();
}
for reading more than one row you can take a look at SqlCommand.ExecuteReader()
You need to use direct database access such as in the System.Data.SqlClient Namespace which is documented here System.Data.SqlClient Namespace.
Basically, look up creating a SQLConnection and SQLCommand and using them to retrieve the data.

How to put IF condition while reading SQL Server query data in C#

Dears,
I'm designing a report in C# using windows form linked to SQL Server table. The result of the query is usually GP% numbers like : 30% or 40% and so on. These numbers are string by the way. I want to put the SQL Server result "30% for example in the array in c#. if no problem with the number it will be added simply like this :
conn.Open();
SqlCommand cmd43 = new SqlCommand(Product1ProfitPercentQuery, conn);
SqlDataReader rd43 = cmd43.ExecuteReader();
while (rd43.Read())
{
string Product1= rd43.GetString(0);
Products.Add(Product1);
}
rd43.Close();
conn.Close();
/But the problem is that some times the query's result is Null. The array will not accept to put Null result. I want to put a condition in the array reader as the following but its't working :/
conn.Open();
SqlCommand cmd43 = new SqlCommand(Product1ProfitPercentQuery, conn);
SqlDataReader rd43 = cmd43.ExecuteReader();
while (rd43.Read())
{
string Product1= rd43.GetString(0);
if (Product1=="Null")
{
Products.Add("0");
}
else if (Product1!= "Null")
{
Products.Add(Product1);
}
}
rd43.Close();
conn.Close();
How can i write this condition please. Thanks in advance.
You can use the HasRows property of the SqlDataReader to see if the recordest was populated or null, and you could wrap your while loop within it.
conn.Open();
SqlCommand cmd43 = new SqlCommand(Product1ProfitPercentQuery, conn);
SqlDataReader rd43 = cmd43.ExecuteReader();
if (rd43.HasRows) {
while (rd43.Read())
{
string Product1= rd43.GetString(0);
Products.Add(Product1);
}
}
rd43.Close();
conn.Close();
You need to check SqlDataReader.IsDBNull(0) in your if statement like below:
if (rd43.IsDBNull(0))
{
Products.Add("0");
}
else
{
Products.Add(rd43.GetString(0));
}
More information about it you can find here
If the column is null, the reader will return a SQL DBNull value, not a string representation of null. Try something like this:
string Product1= rd43.GetString(0);
if(rd43.IsDBNull(Product1))
{
Products.Add("0");
}
else
{
Products.Add(Product1);
}

Getting column information in SQL

I am somwhat new to SQL, so I am not sure I am going about this the right way.
I am trying to fetch data from my SQL Server database where I want to find out if checkedin is 1/0, but it needs to search on a specific user and sort after the newest date as well.
What I am trying to do is something like this:
string connectionString = ".....";
SqlConnection cnn = new SqlConnection(connectionString);
SqlCommand checkForInOrOut = new SqlCommand("SELECT CHECKEDIN from timereg ORDER BY TIME DESC LIMIT 1 WHERE UNILOGIN = '" + publiclasses.unilogin + "'", cnn);
So my question, am I doing this right? And how do I fetch the data collected, if everything was handled correctly it should return 1 or 0. Should I use some sort of SqlDataReader? I am doing this in C#/WPF
Thanks
using (SqlDataReader myReader = checkForInOrOut.ExecuteReader())
{
while (myReader.Read())
{
string value = myReader["COLUMN NAME"].ToString();
}
}
This is how you would read data from SQL, but i recommend you looking into Parameters.AddWithValue
There are some errors in your query. First WHERE goes before ORDER BY and LIMIT is an MySql keyword while you are using the Sql Server classes. So you should use TOP value instead.
int checkedIn = 0;
string cmdText = #"SELECT TOP 1 CHECKEDIN from timereg
WHERE UNILOGIN = #unilogin
ORDER BY TIME DESC";
string connectionString = ".....";
using(SqlConnection cnn = new SqlConnection(connectionString))
using(SqlCommand checkForInOrOut = new SqlCommand(cmdText, cnn))
{
cnn.Open();
checkForInOrOut.Parameters.Add("#unilogin", SqlDbType.NVarChar).Value = publiclasses.unilogin;
// You return just one row and one column,
// so the best method to use is ExecuteScalar
object result = checkForInOrOut.ExecuteScalar();
// ExecuteScalar returns null if there is no match for your where condition
if(result != null)
{
MessageBox.Show("Login OK");
// Now convert the result variable to the exact datatype
// expected for checkedin, here I suppose you want an integer
checkedIN = Convert.ToInt32(result);
.....
}
else
MessageBox.Show("Login Failed");
}
Note how I have replaced your string concatenation with a proper use of parameters to avoid parsing problems and sql injection hacks. Finally every disposable object (connection in particular) should go inside a using block

SqlDataReader returns null unexpectedly

I have a simple connection to a SQL Server that is not working. I'm trying to read data from it using a SqlDataReader in C#.
Here is the code:
bool ok = false;
SqlConnection con = new SqlConnection();
con.ConnectionString = #"********";
SqlCommand cmd = new SqlCommand();
cmd.Parameters.AddWithValue("#a", uname);
cmd.Parameters.AddWithValue("#b", pass);
cmd.CommandText = #"SELECT username FROM admins WHERE pass='#b'";
cmd.Connection = con;
SqlDataReader r;
con.Open();
r = cmd.ExecuteReader();
r.Read();
string n;
n = r.GetString(0);
if (n != null)
{
ok = true;
}
con.Close();
if (ok)
{
Session["admin"] = uname;
Response.Redirect("admin_page.aspx");
}
else
{
eror.Text = "An eror occured";
Response.Redirect("index.aspx#work");
}
Note: that in the above code string "uname" and "pass" are definitely not null.
Note #2 : I did try running the r.read() in a while loop (even though it's not possible to have more then one row) ---> same result.
I tried running this code in step mode, and it appears that it breaks on this line:
n = r.GetString(0);
With this exception:
An exception of type 'System.InvalidOperationException' occurred in System.Data.dll but was not handled in user code
Additional information: Invalid attempt to read when no data is present.
I'm kinda lost here. I know that it's probably a simple thing I missed here, I just can't find it. Any ideas?
In addition to Amit's observation about an unused parameter, you are misusing the parameter
Where you have
cmd.CommandText = #"SELECT username FROM admins WHERE pass='#b'";
you should not have quotes around the value, so:
cmd.CommandText = #"SELECT username FROM admins WHERE pass=#b";
The parameter will know it is a VARCHAR
Your not using SqlDataReader correctly.
If you want to know whether there exists a user with the correct username and password, your query should probably be: SELECT 1 FROM admins WHERE username=#a AND pass=#b
Once that's done, and since you don't care what the selected value is (you only care that there was a returned row...) Use the command like this:
r = cmd.ExecuteReader();
ok = r.HasRows;
After this, continue as you did.

Categories