Retrieve data from DataGridView to TEXTBOXS - c#

I have this code:
private void dataGridView2_CellClick(object sender,DataGridViewCellEventArgs e)
{
cmd.Connection = cn;
cmd.CommandText = "select * from subdiseases where id_subdiss=" + dataGridView2.SelectedRows[0].Cells[0].Value;
if (cn.State == ConnectionState.Open)
{
cn.Close();
}
cn.Open();
SqlDataReader dr4 = null;
dr4 = cmd.ExecuteReader() ;
while (dr4.Read())
{
a = dr4["id_diss"].ToString();
comboBox1.Text = dr4["name_diss"].ToString();
namesub.Text = dr4["name_subdiss"].ToString();
namedet.Text = dr4["details"].ToString();
}
dr4.Close();
}
I get this error:
Invalid attempt to call Read when reader is closed.

As someone mentioned in a comment below your post, make sure that you're getting this error on the very method that you posted, as it looks fine to me. Normally you would get this error if you closed the reader inside your loop or if you tried reading it on a closed db connection. You might want to try to just open the connection once at the beginning and closing it once at the end, removing that open close validation you have, although that shouldn't be the issue.

Related

Method name expected C# SQL Server visual studio 2019 [duplicate]

This question already has answers here:
Read data from SqlDataReader
(13 answers)
Closed 2 years ago.
I'm trying to read data from the data source and I got this error in the ExecuteReader method,
When I try to show the result in some label.
I'm getting the error here idlabel.Text = myraeder("id"); under myreader varibale
private void Searchbtn_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(dataConnectin);
con.Open();
string searchsql = "SELECT * from Table WHERE Name=" + searchtxt.Text + "";
SqlCommand cmd = new SqlCommand(searchsql, con);
SqlDataReader myraeder;
myraeder = cmd.ExecuteReader();
myraeder.Read();
idlabel.Text = myraeder("id");
}
Use square brackets instead of round brackets.
Convert the field to string.
idlabel.Text = myraeder["id"].ToString();
Read the data in this way:
idlabel.Text = myraeder["id"].ToString();
con.Close();
And do not forget to close the connection after getting required data.
There are so many errors that are obvious. Let me show you a better way to write code. Follow me!
Give the variables proper names and casing.
Use asynchrony.
Use parameters in sql queries.
Release resources by wrapping them in using.
Enclose names in brackets in sql.
private async void SearchButton_Click(object sender, EventArgs e)
{
using (var connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
string searchSql = "SELECT * from [Table] WHERE [Name]=#name";
using (var command = new SqlCommand(searchSql, connection))
{
command.Parameters.Add("name", SqlDbType.NVarChar).Value = searchTextBox.Text;
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
idLabel.Text = reader["id"].ToString();
}
}
}
}
}

Getting a "There is already an open DataReader associated with this Command which must be closed first" error

Even though I call close() on the reader, I still get the following error message:
There is already an open DataReader associated with this Command which must be closed first
It is only happening when there are 2 or more empty Document_No fields.
if (textBoxDocNum.Text == "")
{
SqlConnection baglanti = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=E:\Visual\sw\sw\DMSDataBase.mdf;Integrated Security=True");
baglanti.Open();
SqlCommand emir = new SqlCommand("SELECT Document_No, Doc_IDN FROM Details WHERE Document_No = ''", baglanti);
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(emir);
da.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
SqlCommand emir2 = new SqlCommand("SELECT Class, Type, Title, State, Date, Status FROM Document WHERE IDN = "+dr["Doc_IDN"].ToString(), baglanti);
SqlDataReader dr2 = emir2.ExecuteReader(); //it explodes here
dr2.Read();
if (dr2[0].ToString()==comboBoxClass.Text && dr2[1].ToString() == comboBoxType.Text && dr2[2].ToString() == textBoxTitle.Text && dr2[3].ToString() == State && dr2[5].ToString() == Status)
{
labelDuplicate.Visible = true;
return 0;
}
dr2.Close();
baglanti.Close();
}
}
I think your issue might be that when you return from inside the if statement, the reader will not be closed.
You should change your code to use using statements. That will close your reader even if you return. The same is true for the connection.
Your code has another flaw. I believe readers require an open connection. The first pass around the loop will close the connection if the condition is false, making the second pass fail.

How do I take sql results and populate labels in my header?

I am attempting to change my code. I am in the process of learning while I code and many parts of my C#/ASP.Net application use LINQ to SQL and many parts use commands to directly access the sql database. I felt like I should standardize these, so I am changing over the LINQ to SQL code. I have a portion of the code that takes the finds one record based on a session variable and then populates the labels in my header with the sql query results. here is the code:
protected void Page_Load(object sender, EventArgs e)
{
var pinNum = MySession.Current.focusParcel;
if (pinNum != 0)
{
String sql = ConfigurationManager.ConnectionStrings["Recorder"].ConnectionString;
SqlConnection connection = new SqlConnection(sql);
connection.Open();
SqlCommand command = new SqlCommand("Select PARCEL, PIN_TXT, Owner, Address1, Address2, CSZ, ACRES, LEGAL, Active FROM[ParcelView] WHERE PARCEL = " + pinNum, connection);
SqlDataReader selectedParcel = command.ExecuteReader();
if (selectedParcel != null)
{
lblPIN_Num.Text = selectedParcel["PARCEL"].ToString();
lblPIN_TXT.Text = selectedParcel["PIN_TXT"].ToString();
lblDateTime.Text = DateTime.Now.ToString("MMMM dd, yyyy");
lblOwner.Text = selectedParcel["Owner"].ToString();
lblAddress1.Text = selectedParcel["Address1"].ToString();
lblAddress2.Text = selectedParcel["Address2"].ToString();
lblCSZ.Text = selectedParcel["CSZ"].ToString();
lblAcres.Text = string.Format("{0} Acres", selectedParcel["ACRES"]);
lblLegal.Text = selectedParcel["LEGAL"].ToString();
if (selectedParcel["Active"].ToString() == "A")
{
lblInactive.Text = " (ACTIVE)";
}
else
{
lblInactive.Text = " (INACTIVE)";
lnkAddDocument.Visible = false;
}
}
lblCurrentUser.Text = Page.User.Identity.Name;
connection.Close();
}
else
Response.Redirect("./ParcelSearch.aspx");
}
I am receiving the following error:
Invalid attempt to read when no data is present.
I know the SQL statement used will return a record when it is used directly into sql query of database.
Thanks in advance for any advice. Should I be concerned about the lack of consistency in accessing data across the application at all? If so, should I be converting everything to LINQ? Or converting everything away from LINQ? I klnow of the existence of MVC and know I should learn it and use it, but I am too far down the path to try to convert there right now.
Change
if (selectedParcel != null)
To
if (selectedParcel.Read())
You have to read a record in the data reader before you can start pulling data. Its a forward only cursor that starts off not pointing to a record. The Read() method advances the reader by 1 and returns true/false if it was successful.
Note that it is not necessary to call HasRows if use the code above. The if block will only be entered if there is a row, if there is not then Read returns false and the block is not entered.
Edit
There are many bad practices in your code.
Use parameterized sql!! This is the most important thing you can take away here!
Wrap your connections in using blocks to ensure the connection is ALWAYS closed.
Sql code changes
String sql = ConfigurationManager.ConnectionStrings["Recorder"].ConnectionString;
using(SqlConnection connection = new SqlConnection(sql))
using(SqlCommand command = new SqlCommand("Select PARCEL, PIN_TXT, Owner, Address1, Address2, CSZ, ACRES, LEGAL, Active FROM [ParcelView] WHERE PARCEL = #pinNum", connection))
{
command.Parameters.Add(new SqlParameter("#pinNum", SqlDbType.VarChar){Value = pinNum});
connection.Open();
using(SqlDataReader selectedParcel = command.ExecuteReader())
{
if (selectedParcel.Read())
{
/*code unchanged*/
}
}
/* 1 line code unchanged*/
}
Once you have executed the command you need to actually read the data :
SqlDataReader selectedParcel = command.ExecuteReader();
if (selectedParcel.HasRows)
{
selectedParcel.Read();
....
....
I recommend you use this format for your sqlDatareader instead, as it it will parse whether results have been retrieved or not, and will automatically dispose itself on exception:
using(SqlDataReader selectedParcel = command.ExecuteReader())
{
while (selectedParcel .Read())
{
//Assign label text to results
}
}
You should Read() the SqlDataReader.
protected void Page_Load(object sender, EventArgs e)
{
var pinNum = MySession.Current.focusParcel;
if (pinNum == 0)
Response.Redirect("./ParcelSearch.aspx");
String sql = ConfigurationManager.ConnectionStrings["Recorder"].ConnectionString;
using(SqlConnection connection = new SqlConnection(sql))
{
connection.Open();
SqlCommand command = new SqlCommand("Select PARCEL, PIN_TXT, Owner, Address1, Address2, CSZ, ACRES, LEGAL, Active FROM[ParcelView] WHERE PARCEL =#PinNum ", connection);
//protect from sql injection
command.Parameters.AddWithValue(#PinNum, pinNum);
using(SqlDataReader selectedParcel = command.ExecuteReader())
{
if(!selectedParcel.HasRows)
return;
SetLabels(selectedParcel);
}
}
}
private void SetLabels(SqlDataReader selectedParcel)
{
lblPIN_Num.Text = selectedParcel["PARCEL"].ToString();
lblPIN_TXT.Text = selectedParcel["PIN_TXT"].ToString();
lblDateTime.Text = DateTime.Now.ToString("MMMM dd, yyyy");
lblOwner.Text = selectedParcel["Owner"].ToString();
lblAddress1.Text = selectedParcel["Address1"].ToString();
lblAddress2.Text = selectedParcel["Address2"].ToString();
lblCSZ.Text = selectedParcel["CSZ"].ToString();
lblAcres.Text = string.Format("{0} Acres", selectedParcel["ACRES"]);
lblLegal.Text = selectedParcel["LEGAL"].ToString();
if (selectedParcel["Active"].ToString() == "A")
{
lblInactive.Text = " (ACTIVE)";
}
else
{
lblInactive.Text = " (INACTIVE)";
lnkAddDocument.Visible = false;
}
lblCurrentUser.Text = Page.User.Identity.Name;
}
I refactor your code to look a little bit. You had different problems as not closing your Reader. You was open to sql injection, also you should transfer the connection to Db in separate class.

Assigning SQL reader leaves code

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.

Saving data from datagridview to SQL Server database

Below is code in which I have written only save first row value in database but when I try to save multiple row value it gives an error. I don't know how to use loop in this code and where to use loop to insert multiple rows in database at once.
How do I save DataGridView values into a SQL Server database?
private void button1_Click(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand("INSERT INTO datagrid (sr, name, email, tel_no) VALUES(#c1,#c2,#c3,#c4)", cs);
{
cmd.Parameters.Add(new SqlParameter("#C1", SqlDbType.VarChar));
cmd.Parameters.Add(new SqlParameter("#C2", SqlDbType.VarChar));
cmd.Parameters.Add(new SqlParameter("#C3", SqlDbType.VarChar));
cmd.Parameters.Add(new SqlParameter("#C4", SqlDbType.VarChar));
cs.Open();
foreach (DataGridViewRow row in dataGridView1.Rows)
{
{
if (!row.IsNewRow)
{
cmd.Parameters["#C1"].Value = row.Cells[0].Value;
cmd.Parameters["#C2"].Value = row.Cells[1].Value;
cmd.Parameters["#C3"].Value = row.Cells[2].Value;
cmd.Parameters["#C4"].Value = row.Cells[3].Value;
cmd.ExecuteNonQuery();
}
cs.Close();
}
}
}
}
There's some information that would be nice to have that you didn't put in your original question:
cs is most likely a SqlConnection, and since you say it works inserting one row I'm guessing it's a global (class level) variable and is created somewhere else. I would do a little bit differently (see my code example for the reason why).
What error are you getting? Based on the problem description, I'll bet it is a closed connection (because you're closing it at the end of your foreach code block, when you should be closing it outside the foreach code block).
So, with that said, here's something that might do the trick for you:
private void button1_Click(object sender, EventArgs e)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
cs.Open();
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (!row.IsNewRow)
{
using (SqlCommand cmd = new SqlCommand("INSERT INTO datagrid (sr, name, email, tel_no) VALUES(#c1,#c2,#c3,#c4)", conn))
{
cmd.Parameters.AddWithValue("#C1", row.Cells[0].Value);
cmd.Parameters.AddWithValue("#C2", row.Cells[1].Value);
cmd.Parameters.AddWithValue("#C3", row.Cells[2].Value);
cmd.Parameters.AddWithValue("#C4", row.Cells[3].Value);
cmd.ExecuteNonQuery();
}
}
}
}
}
In the example above, I use using blocks for the SqlConnection and SqlCommand objects. The using block ensures that the resources are properly cleaned up when the using block is exited - this way you don't have to worry about things like when to call conn.Close(), as the using block will take care of that for you.
Also, I create the SqlConnection in the method. The connectionString in this case would be a string variable (at the class level, so all methods that need it can access it) holding the connection string.
Finally, I create the SqlCommand in the if block, which will only be entered if the !row.IsNewRow expression evaluates to true. I'm not 100% sure you can reassign values to a an existing command's parameters (most likely you can, but...)
I would also suggest including some error handling in case something goes wrong with the insert.
Hopefully this addresses the questions/issues you have. If not, please provide more detail so we can better assist you. Happy coding!
The problem is that cs is closed more times than it is opened.
You open the connection, insert, but then try to close for each iteration.
Either you should open a connection for each iteration, or you should see how to do everything with only only connection.
int ab;
int PIrowss = dataGridView2.Rows.Count;
for (ab = 0; ab < PIrowss; ab++)
{
PiCGetAutID();
purchaeOrder.pcautoid = Catget;
purchaeOrder.ponum = label119.Text;
purchaeOrder.col1 = dataGridView2.Rows[ab].Cells[0].Value.ToString();
purchaeOrder.col2 = dataGridView2.Rows[ab].Cells[1].Value.ToString();
purchaeOrder.col3 = dataGridView2.Rows[ab].Cells[2].Value.ToString();
purchaeOrder.col4 = dataGridView2.Rows[ab].Cells[3].Value.ToString();
purchaeOrder.col5 = dataGridView2.Rows[ab].Cells[4].Value.ToString();
purchaeOrder.POcSave();
}
private void button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection();
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
string sr = null;
string name = null;
string email = null;
string tel_no = null;
for (int i = 0; i <= this.DataGridView1.Rows.Count; i++) {
sr == this.DataGridView1.Rows(i).Cells(0).Value.ToString()
name == this.DataGridView1.Rows(i).Cells(1).Value.ToString()
email == this.DataGridView1.Rows(i).Cells(2).Value.ToString()
tel_no == this.DataGridView1.Rows(i).Cells(3).Value.ToString()
comm.CommandText = "insert into mytable(name,age) values('" & name & "','" & age& "')"
comm.ExecuteNonQuery()
conn.Close()
}
}
Try this and see. It should work

Categories