I am currently programming a C# program that lets students log into an interface, check grades, etc.. Admins can create new users. The student IDs are 9-digit codes that all begin with "95." When an admin is creating a new user, I want to go through the database to make sure that the ID number they have entered isn't already taken.
To do this, I have the following code:
connection.Open();
readerUsers = commandUsers.ExecuteReader();
while (readerUsers.Read())
{
MessageBox.Show(readerUsers[2].ToString());
if(readerUsers[2].ToString() == IDNum)
{
userAlreadyExists = true;
break;
}
}
connection.Close();
And in my Users table, which readerUsers and commandUsers are connected to, I have the following:
IDuser Username 95Number Password Active Admin
-------------------------------------------------------------
1 sward 951619984 uo99lb True True
... ... ... ... ... ...
Now, when I went to test my code by creating a user with the ID number of 951619984 (a number already entered in the database), userAlreadyExists would still remain false. So I made the program show a message box of each item in the 95Number column (which is of type Ntext). Every time, the message box would only show "95".
I am very new to programming with databases, so I apologize if this is a very newby question, but I'm not sure what to do to get the whole string from this ntext column. Could someone explain what I'm doing wrong? Thank you for your time.
Here is a better way of doing that:
var connstr = ConfigurationManager.ConnectionStrings["your key"].ConnectionString;
var sql = "SELECT COUNT(*) FROM Users WHERE [95number]=#num";
using (var conn = new SqlConnection(connstr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("num",SqlDbType.Int).Value = IDNum;
conn.Open();
var result = cmd.ExecuteScalar();
userAlreadyExists = result > 0;
}
I did mines this way.
string Qstring = "Select 95number where 95number = '95#########'";
using (SqlConnection Con = new SqlConnection(Form1.ConnectionStringGen))
using (SqlCommand Com = con.CreateCommand())
{
Com.CommandText = Qstring;
con.Open();
using (SqlDataReader Reader = Com.ExecuteReader())
{
if(Reader.Read())
{
string 95Numb = Reader["95Number"].ToString();
Messagebox.show(95Numb);
userAlreadyExists = true;
//meaning if the reader reads an item it will prompt
}
else
{
userAlreadyExists = false;
}
}
con.Close();
}
}
catch (Exception)
{
throw;
}
Related
I have a simple database that I am using. It contains two entries for users which is a user with UserID 1 and IsAdmin 0 and another with UserID 3041234567 and IsAdmin of 1. The only fields in the database is a string UserID and a bit IsAdmin. I am reading from the database with the following code:
SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn);
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Users WHERE UserID = " + t.Text.ToString(), conn);
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
user.UserID = reader["UserID"].ToString();
user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
}
}
conn.Close();
If I enter the number 3041234567 as the UserID everything works perfectly, but If I enter the number 1 I get an exception saying that "The conversion of the nvarchar value '3041234567' overflowed an int column."
If I set a breakpoint and watch the while(reader.read()) loop the loop iterates through fine and sets the user.UserID = 1 and the user.IsAdmin = false. The exception is thrown when the loop begins to iterate a second time. I guess I have a couple of questions:
Why is the loop iterating a second time?
How is the ID 3041234567 being returned with the sql command "SELECT * FROM Users WHERE UserID = 1"
What is the int column that is being overflowed?
Well, since
3041234567 > int.MaxValue ( == 2147483647)
you've got an overflow; if you want some kind of integer value, however, try long (which is 64 bit long):
long value = Convert.ToInt64(reader["UserID"]);
Something like this:
// Wrap IDisposable into using
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn)) {
conn.Open();
// Make sql
// 1. Readable
// 2. Parametrized
// 3. Avoid * in select
String sql =
#"select UserID,
IsAdmin
from Users
where UserID = #prm_UserId";
// Wrap IDisposable into using
using (SqlCommand cmd = new SqlCommand(sql, conn)) {
// Explicit data type will be better here (Add Parameter with type)
// but I don't know it
cmd.Parameters.AddWidthValue("prm_UserId", t.Text);
// Wrap IDisposable into using
using (SqlDataReader reader = cmd.ExecuteReader()) {
// You don't want to iterate the whole cursor, but the first record
if (reader.Read()) {
//TODO: Make UserID being "long"
user.UserID = Convert.ToInt64(reader["UserID"]);
user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
}
}
}
}
I am having an issue with my c# code. I am trying to check if a username exists already so I have a select statement but when I breakpoint it, it leaves the code right after I assign the reader. Here is my code:
SqlConnection conn = new SqlConnection(Properties.Settings.Default.CategoriesConnectionString);
SqlCommand chkUser = new SqlCommand("SELECT [Username] FROM [Accounts] WHERE [Username] = #username", conn);
chkUser.Parameters.AddWithValue("#username", txtUsername.Text);
conn.Open();
SqlDataReader sqlReader = chkUser.ExecuteReader(); //leaves code right here
if (sqlReader.HasRows)
{
MessageBox.Show("That username already exists. Please choose another.");
txtUsername.Focus();
return;
}
conn.Close();
I figure it is because there is nothing in the table yet but I don't know why it is not checking whether or not it has rows and is just leaving.
Any help is appreciated. Thanks
Some more information on the issue would be useful. Seems like you are getting an exception for some reason (as #Guffa said) and without any further details it becomes difficult guessing what the reason is. Try changing the code you posted to the following:
using(SqlConnection conn = new SqlConnection(Properties.Settings.Default.CategoriesConnectionString))
using(SqlCommand chkUser = new SqlCommand("SELECT [Username] FROM [Accounts] WHERE [Username] = #username", conn))
{
chkUser.Parameters.AddWithValue("#username", txtUsername.Text);
try
{
conn.Open();
using(SqlDataReader sqlReader = chkUser.ExecuteReader())
{
if (sqlReader.HasRows)
{
MessageBox.Show("That username already exists. Please choose another.");
txtUsername.Focus();
return;
}
}
}
catch(Exception e)
{
// manage exception
}
}
and see if something changes. In case it doesn't try debugging and see what kind of exception it throws.
Here is an example that i use in a login scenario where i've stored usernames in a mysql database table.
Even though i use MySQL there shouldnt be much of a difference.(not sure about this though).
public static string CheckUsername()
{
bool usernameCheck = false;
InitiateDatabase();//contains the root.Connection string
MySqlCommand readCommand = rootConnection.CreateCommand();
readCommand.CommandText = String.Format("SELECT username FROM `SCHEMA`.`USERTABLE`");
rootConnection.Open();
MySqlDataReader Reader = readCommand.ExecuteReader();
while (Reader.Read())
{
for (int i = 0; i < Reader.FieldCount; i++)
{
if (Reader.GetValue(i).ToString() == USERNAME_STRING)
{
usernameCheck = true;
}
}
}
rootConnection.Close();
if (usernameCheck)
{
return "Succes";
}
else
{
return "Wrong Username!";
}
}
This is of course without exception handling, which you might find useful during testing and if its meant to be used by others.
this is how I select some content twice and when I get into the middle to select so like that it gives me trouble to select something on file.
The problem I have never seen before,
I think it's something with conn.open() and Conn.Close()
my code looks like this:
int prisId = Convert.ToInt32(Request.QueryString["Id"]);
cmd.Parameters.AddWithValue("#ppId", prisId);
cmd.CommandText = "SELECT priser FROM Priser WHERE Id = #ppId;";
conn.Open();
SqlDataReader readerPriser = cmd.ExecuteReader();
if (readerPriser.Read())
{
PanelerrorHandelsbetingelser.Visible = false;
string Brugerid = Session["id"].ToString();
cmd.Parameters.AddWithValue("#brugerid", Brugerid);
cmd.CommandText = "SELECT id, brugernavn, fornavn, efternavn FROM brugere WHERE Id = #brugerid;";
SqlDataReader readerBrugerid = cmd.ExecuteReader();
if (readerPriser.Read())
{
Session["id"] = readerBrugerid["id"].ToString();
Session["brugernavn"] = readerBrugerid["brugernavn"].ToString();
Session["fornavn"] = readerBrugerid["fornavn"].ToString();
Session["efternavn"] = readerBrugerid["efternavn"].ToString();
Session["adresse"] = TextBoxAdresse.Text;
Session["post"] = TextBoxPost.Text;
Session["telefon"] = TextBoxTelefon.Text;
Session["prisen"] = readerPriser["priser"].ToString();
LabelErrorBuyNow.Text = " - Yeaaa Jesper!";
}
else
{
LabelErrorBuyNow.Text = " - Der findes intet med dit brugerid!";
}
}
conn.Close();
problems come after line 9-10
The problem is such that it appears this one mistake on my part: There is already an open DataReader associated with this Command which must be closed first.
Always remember to release resources after they are used. So at the method end, you should:
cmd.Parameters.Clear();
readerPriser.Close();
conn.Close();
The exception tells you exactly what is wrong.
You have tried to run two SqlDataReaders over the same connection without either specifying MultipleActiveResultSets=True in your connection string or else first closing the first reader.
You have three options:
Use a second connection to run the second SqlDataReader.
Add "MultipleActiveResultSets=True" to your connection string.
Close the first SqlDataReader before using the second.
You need to close the readerPriser first be
readerPriser.Close();
Then affiliate the same command with next reader.
Always close the readers after using them.
There are two problems here. First of all, you are not placing all of your IDisposable objects into using blocks. Second, you are reusing the same SqlCommand for different queries. Third, your second Read call is using the wrong SqlDataReader.
Try
using (SqlConnection conn = new SqlConnection(...)){
conn.Open();
using (SqlCommand selectPriser = new SqlCommand("SELECT priser FROM Priser WHERE Id = #ppId;", conn))
{
selectPriser.Parameters.AddWithValue("#ppId", prisId);
using (SqlDataReader readerPriser = selectPriser.ExecuteReader())
{
if (readerPriser.Read())
{
// ...
using (SqlCommand selectBrugere = new SqlCommand("SELECT id, brugernavn, fornavn, efternavn FROM brugere WHERE Id = #brugerid;"){
string Brugerid = Session["id"].ToString();
selectBrugere.Parameters.AddWithValue("#brugerid", Brugerid);
using (SqlDataReader readerBrugerid = selectBrugere.ExecuteReader()){
if (readerBrugerid.Read()){
// ...
}
}
}
}
}
}
}
I created a sale table which Insert function does not work properly. It shows the error message like this "ExecuteNonQuery requires an open and available Connection. The connection's current state is closed." If I removed Sql Close Statement on Line 14, it shows this error msg "There is already an open DataReader associated with this Command which must be closed first." My code below work like this. I checked available stocks from my Product table. If quantity order is greater than quantity from Product Table, show error message. Otherwise, proceed to inserting order information into Sale Table. Any help is appreciated.
private void btnOrder_Click(object sender, EventArgs e)
{
int iQuantityDB;
int iCustomerID = Convert.ToInt32(txtCustomerID.Text);
int iProductID = Convert.ToInt32(txtProductID.Text);
decimal dPrice = Convert.ToDecimal(txtPrice.Text);
int iQuantity = Convert.ToInt32(txtQuantity.Text);
decimal dSubtotal = Convert.ToDecimal(txtSubTotal.Text);
decimal dGST = Convert.ToDecimal(txtGST.Text);
decimal dTotal = Convert.ToDecimal(txtTotal.Text);
string strConnectionString = #"Data Source = KK\SQLEXPRESS; Integrated Security = SSPI; Initial Catalog = JeanDB; MultipleActiveResultSets=True;";
using (var sqlconn = new SqlConnection(strConnectionString))
{
sqlconn.Open();
string querySelectQuantity = #"Select Quantity from dbo.JeanProduct WHERE ProductID = #iProductID";
using (var cmdOrder = new SqlCommand(querySelectQuantity, sqlconn))
{
using (var sdRead = cmdOrder.ExecuteReader())
{
sdRead.Read();
iQuantityDB = Convert.ToInt32(sdRead["Quantity"]);
}
}
if (iQuantityDB > iQuantity)
{
string InsertQuery = #"INSERT INTO Sale(CustomerID, ProductID, Price, Quantity, Subtotal, GST, Total)VALUES(#iCustomerID, #iProductID, #dPrice, #iQuantity, #dSubtotal, #dGST, #Total)";
using (var InsertCMD = new SqlCommand(InsertQuery, sqlconn))
{
InsertCMD.Connection = sqlconn;
InsertCMD.Parameters.AddWithValue("#iCustomerID", iCustomerID);
InsertCMD.Parameters.AddWithValue("#iProdcutID", iProductID);
InsertCMD.Parameters.AddWithValue("#dPrice", dPrice);
InsertCMD.Parameters.AddWithValue("#iQuantity", iQuantity);
InsertCMD.Parameters.AddWithValue("#dSubtotal", dSubtotal);
InsertCMD.Parameters.AddWithValue("#dGST", dGST);
InsertCMD.Parameters.AddWithValue("#dTotal", dTotal);
InsertCMD.ExecuteNonQuery();
LoadDataonTable();
}
}
else
{
MessageBox.Show("no more stock");
}
sqlconn.Close();
}
}
You should change your connection string to
string strConnectionString = #"Data Source = KK\SQLEXPRESS;
Integrated Security = SSPI;
Initial Catalog = JeanDB;
MultipleActiveResultSets=True";
And do not close the connection between the Reader.Read and the ExecuteNonQuery.
You need at least Sql Server 2005 for this to work.
The connection used by a SqlDataReader cannot be used for other operations unless you set the connection string with the MultipleActiveResultSets key. Of course you could open two connection objects (with the same connection string) and use one for the SqlDataReader and one to Execute your command.
Not really linked to your problem, but I suggest to use a parameterized query also for the SELECT part of your code.
Moreover, you should use the Using Statement around the disposable object to ensure the proper closing and disposing also in case of exceptions. Finally, the syntax used in the INSERT INTO is not correct. I think that this code could explain some of the points explained above.
string strConnectionString = #"......;MultipleActiveResultSets=True;";
using(SqlConnection sqlconn = new SqlConnection(strConnectionString))
{
sqlconn.Open();
string querySelectQuantity = #"Select Quantity from dbo.JeanProduct
WHERE ProductID = #id";
using(SqlCommand cmdOrder = new SqlCommand(querySelectQuantity, sqlconn))
{
cmdOrder.AddWithValue("#id", Convert.ToInt32(txtProductID.Text));
using(SqlDataReader sdRead = cmdOrder.ExecuteReader())
{
if(sdRead.Read())
{
.....
string InsertQuery = #"INSERT INTO Sale(SaleID, CustomerID, ProductID,
Price, Quantity, Subtotal, GST, Total)VALUES(#iCustomerID,
#iProductID, #dPrice, #iQuantity,
#dSubtotal, #dGST, #Total)";
using(SqlCommand InsertCMD = new SqlCommand(InsertQuery, sqlconn))
{
InsertCMD.Parameters.AddWithValue("#iCustomerID", iCustomerID);
....
InsertCMD.ExecuteNonQuery();
LoadDataonTable();
}
}
else
{
MessageBox.Show("no more stock");
}
}
}
}
You've closed your SqlConnection after the reader execution / read cycle (and in the other error, you've kept the reader open while trying to execute another command).
Either close the reader and leave the connection open for the insert, or open a new connection for the insert.
Better still, use using to handle the disposal of the resources for you, and scope the DB resources to be released as soon as you are done with them, e.g.:
using (var sqlconn = new SqlConnection(strConnectionString))
{
sqlconn.Open();
string querySelectQuantity = "Select Quantity ...";
using var (cmdOrder = new SqlCommand(querySelectQuantity, sqlconn))
{
int iQuantityDB;
using (var sdRead = cmdOrder.ExecuteReader())
{
sdRead.Read();
iQuantityDB = Convert.ToInt32(sdRead["Quantity"]);
} // Dispose reader
// sqlconn.Close(); <-- Don't close
} // cmdOrder disposed here
if (iQuantityDB > iQuantity)
{
string InsertQuery = "INSERT INTO ...";
using var (InsertCMD = new SqlCommand(InsertQuery, sqlconn))
{
// ...
} // InsertCmd disposed here
}
} // Sql Connection disposed here
This will overcome many bugs, such as the one you've got where you are conditionally closing the command + connection in an if branch.
I am developing a WinForm Application in C Sharp on the .net framework.
The database string I am using as of now is
<add key="Conn" value="Data Source=MNTCON016; Database=Overtime_Calculator;Trusted_Connection=True;MultipleActiveResultSets=true" />
As I am using Microsoft SQL Server 2005 for development, I can use 2 data readers simultaneously using the MultipleActiveResultSets property to true as mentioned above.
The Method used to invoke the 2 data readers is as follows:
public static void SignUpControllerDay(DateTime Date, System.Windows.Forms.DataGridView PassedGrid)
{
string sql_SignUp = String.Format(#"SELECT Emp_ID as Emp_ID, Name as Name, Sum(Sum) as Sum FROM
(SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID,
e.First_Name+ ' ' +e.Last_Name as Name,
o.Quantity as Sum
FROM Employee e,OT_Hours o,Position p,Signup_Sheet s
WHERE e.Emp_ID=o.Emp_ID
and e.Emp_ID = s.Employee_ID
and s.Day_Shift = 1
and e.Position_ID = p.Position_ID
and p.Position_Name = 'Controller'
and o.Quantity NOT IN(0.3)
and s.Date = '{0}'
and o.Date <= CONVERT(VARCHAR,'{0}',101) AND o.Date > CONVERT(VARCHAR,DATEADD(YYYY,-1,'{0}'),101) )
as OVERTIME
GROUP BY Emp_ID,Name
ORDER BY Sum", Date);
SqlConnection sqlConn = null;
SqlCommand cmd_SignUp;
SqlDataReader dr_SignUp;
try
{
sqlConn = new SqlConnection(databaseConnectionString);
sqlConn.Open();
cmd_SignUp = new SqlCommand(sql_SignUp, sqlConn);
dr_SignUp = cmd_SignUp.ExecuteReader();
while (dr_SignUp.Read())
{
ArrayList arrPhone = new ArrayList();
string sql_Phone = String.Format("SELECT Phone_Number FROM Contact_Details WHERE Emp_ID = {0}", dr_SignUp["Emp_ID"]);
SqlCommand cmd_Phone = new SqlCommand(sql_Phone, sqlConn);
SqlDataReader dr_Phone = cmd_Phone.ExecuteReader();
while (dr_Phone.Read())
{
arrPhone.Add(dr_Phone["Phone_Number"].ToString());
}
//--Retrieving Sectors
ArrayList arrSector = new ArrayList();
string sql_Sector = String.Format(#"SELECT e1.EMP_ID,
( SELECT cast(Sector_ID as varchar(10)) + ';'
FROM Employee_Sector_relationship e2
WHERE e2.Emp_ID = e1.Emp_ID
ORDER BY Sector_ID
FOR XML PATH('') ) AS Sectors
FROM Employee_Sector_Relationship e1
WHERE Emp_ID = {0}
GROUP BY Emp_ID ", dr_SignUp["Emp_ID"]);
SqlCommand cmd_Sector = new SqlCommand(sql_Sector, sqlConn);
SqlDataReader dr_Sector = cmd_Sector.ExecuteReader();
while (dr_Sector.Read())
{
arrSector.Add(dr_Sector["Sectors"].ToString());
}
if (arrSector.Count == 0)
{ arrSector.Add(" "); }
if (arrPhone.Count == 0)
{ arrPhone.Add(" "); }
//--
if (arrPhone.Count == 2)
{
PassedGrid.Rows.Add(dr_SignUp["Emp_ID"].ToString(), dr_SignUp["Name"].ToString(), arrSector[0], dr_SignUp["Sum"], arrPhone[0], arrPhone[1]);
}
else
{
PassedGrid.Rows.Add(dr_SignUp["Emp_ID"].ToString(), dr_SignUp["Name"].ToString(), arrSector[0], dr_SignUp["Sum"], arrPhone[0]);
}
}
}
catch (Exception e)
{
MessageBox.Show("Error found in SignUpControllerDay..." + Environment.NewLine + e.ToString());
}
finally
{
if (sqlConn != null)
{
sqlConn.Close();
}
}
}
Everything works fine.
Now the real problem. I have been informed that the production SQL server for the application to go live is Microsoft SQL server 2000. After doing a bit research, I came to know that Microsoft server 2000 does not support multiple active results sets propery. In short, it does not allow me to use 2 data readers simultaneously.
I need to know how to read the data from 2 different tables, simultaneously, with regards to SQL Server 2000.
Are there any other ways that i can read data as I have mentioned in the code..
Please help..
the application is almost done and is ready to go to production. but MS server 2000 doesnt allow the applcaition to work accordingly...
please help
You can have two active datareaders in Sql Server 2000 by simply creating two connections.
To demonstrate this, I must first berate you for using two very poor practices: dynamic sql and arraylists. Neither have any place in your code. You should also read up on the using construct, though you have my apologies and condolences on "using" and "arraylists" if you're still using .net 1.1.
That said, here's how the code should look:
string sql_Phone = "SELECT Phone_Number FROM Contact_Details WHERE Emp_ID = #EmpID";
using (SqlConnection cn2 = new Sqlconnection(databaseConnectionString))
using (SqlCommand cmd_Phone = new SqlCommand(sql_Phone, cn2))
{
cmd_Phone.Parameters.Add("#EmpID", SqlDbType.Int);
cn2.Open();
while (dr_SignUp.Read())
{
List<string> arrPhone = new List<string>();
cmd_Phone.Parameters[0].Value = dr_SignUp["Emp_ID"];
using (SqlDataReader dr_Phone = cmd_Phone.ExecuteReader())
{
while (dr_Phone.Read())
{
arrPhone.Add(dr_Phone["Phone_Number"].ToString());
}
}
Also, looking at your code I suspect what you really need to do is re-write your sql. You can combine all those into a single query that you just bind directly to the grid.
Sure:
public void SignUpControllerDay()
{
using (var conn = new SqlConnection(ConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT ...";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var phone = reader["Phone_Number"].ToString();
Bar(phone);
}
}
}
}
public void Bar(string phone)
{
using (var conn = new SqlConnection(ConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT ..."; // use phone to prepare statement
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// Fill the grid
}
}
}
}
You could open multiple database connections with 1 reader per connection
You could also add MultipleActiveResultSets=True; to the connection string, even though it's not recommended.
so, it is not possible! as simple as that the only answer!
multiple connection is a workaroud!
one connection can not handle multiple recordsets simultaneously