open DataReader associated with this Command which must be closed first - asp.net

The following code is for binding a grid:
protected void BindGrid()
{
using (clsDt.sqlCnn)
{
clsDt.sqlCnn.Open();
SqlCommand cmd = new SqlCommand("USP_CRUD_JWELORDERS", clsDt.sqlCnn);
cmd.Parameters.Add(new SqlParameter("#operation", SqlDbType.VarChar, 20));
cmd.Parameters["#operation"].Value = "Display";
cmd.CommandType = CommandType.StoredProcedure;
grdView.DataSource = cmd.ExecuteReader();
grdView.DataBind();
clsDt.sqlCnn.Close();
}
}
and following for binding the dropdown on the same page:
protected void ddparticular(DropDownList ddlParticular)
{
DataTable dt = new DataTable();
ddlParticular.DataSource = clsDt.getDataTable("SELECT COM_CMCD,COM_CMNM FROM COM_MST WHERE COM_CMCD = (SELECT COM_CMCD FROM COM_TYP WHERE COM_CTNM = 'Jewellery')");
ddlParticular.DataTextField = "COM_CMNM";
ddlParticular.DataValueField = "COM_CMCD";
ddlParticular.DataBind();
}
but when running it shows:
There is already an open DataReader associated with this Command which must be closed first

The only thing I can see straight off the bat is binding a grid view to a data reader, which I'm not sure would work (you have to invoke reader.Read() to get rows), it may just never actually read, and never close the connection since the reader isn't finished (I may be wrong about that).
Out of interest, try replacing this:
grdView.DataSource = cmd.ExecuteReader();
grdView.DataBind();
with:
var dt = new DataTable();
var reader = cmd.ExecuteReader();
dt.Load(reader);
grdView.DataSource = dt;
grdView.DataBind();
I've had some fair issues with datareaders binding to grid views, this is the way I usually do it now.

Related

Error: There is no row at position 0 in asp.net

I wrote this code to get data from gridview to display down the controls, but it failed:
There is no row at position 0.
at line:
txtSTT.Text = ds.Tables["Trailer"].Rows[0].ItemArray.GetValue(0).ToString();
Full code:
protected void btnSua_Click(object sender, EventArgs e)
{
string STT = ((LinkButton)sender).CommandArgument;
SqlConnection conn = new SqlConnection(#"Data Source=DESKTOP-R8LG380\SQLEXPRESS;Initial Catalog=PHIM;Integrated Security=True");
string query = "SELECT * FROM Trailer WHERE STT = '" + STT + "'";
SqlCommand cmd = new SqlCommand(query, conn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds, "Trailer");
txtSTT.Text = ds.Tables["Trailer"].Rows[0].ItemArray.GetValue(0).ToString();
txtMaTrailer.Text = ds.Tables["Trailer"].Rows[0].ItemArray.GetValue(1).ToString();
cmbMaPhim.SelectedValue = ds.Tables["Trailer"].Rows[0].ItemArray.GetValue(2).ToString();
txtUrlTrailer.Text = ds.Tables["Trailer"].Rows[0].ItemArray.GetValue(3).ToString();
txtGhiChu.Text = ds.Tables["Trailer"].Rows[0].ItemArray.GetValue(4).ToString();
txtSTT.ReadOnly = true;
txtSTT.Visible = true;
lbSTT.Visible = true;
}
From the error message, I would say your query is not returning any rows.
Try putting a break point right after the assignment to the queryand copy the string into a query window in SQL Server Management Studio to see if any rows of data come back.
It is probably not returning any rows. Debug your query until you know you have one that returns data.
Also, In addition to putting the contents of this function in a try/catch block, I would wrap all the lines that use ds.Tables["Trailer"].Rows[0] in an if block, something like if(ds.Tables["Trailer"].Rows.Count > 0){

setting a dropdownlist value from database on page load

Sounds like an easy job but havent been able to figure it out.I have an edit profile page where all the user data is pulled from database to respective textboxes,labels etc on Page_Load.The dropdownlist is binded to a table as below.My ddl is as below :
<asp:DropDownList ID="ddlGender" runat="server" Width="160px" AutoPostBack="True" OnDataBound="ddlGender_DataBound">
</asp:DropDownList>
and is binded as below :
protected void BindGenderDropDown()
{
string CS = ConfigurationManager.ConnectionStrings["SportsActiveConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
con.Open();
SqlCommand cmd = new SqlCommand("select * from tblGenders", con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
ddlGender.DataSource = ds;
ddlGender.DataTextField = "GenderName";
ddlGender.DataValueField = "GenderId";
ddlGender.DataBind();
}
ddlGender.Items.Insert(0, new ListItem("---Select---", "0"));
ddlGender.SelectedIndex = 0;
}
I am not able to set a value in the dropdownlist though.Here is what I have done :
private void ExtractData()
{
string CS = ConfigurationManager.ConnectionStrings["fgff"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
con.Open();
SqlCommand cmd = new SqlCommand("Select * from tblRegPlayers1 where UserId='PL00011'", con);
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
string path = rdr["ProfilePicPath"].ToString();
hfImagePath.Value = Path.GetFileName(path);
txtFName.Text = rdr["FirstName"].ToString();
txtLName.Text = rdr["LastName"].ToString();
txtEmailAddress.Text = rdr["EmailAdd"].ToString();
txtContactNumber.Text = rdr["MobileNo"].ToString();
txtdob.Value = rdr["DOB"].ToString();
txtStreetAddress.Text = rdr["StreetAddress"].ToString();
txtZipCode.Text = rdr["ZipCode"].ToString();
ddlGender.Items.FindByText(rdr["Gender"].ToString()).Selected = true;
}
}
But it says 'Object is not set to an instance'. So i played around a bit and tried doing it in DataBound like this :
protected void ddlGender_DataBound(object sender, EventArgs e)
{
string CS = ConfigurationManager.ConnectionStrings["SportsActiveConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
con.Open();
SqlCommand cmd = new SqlCommand("Select * from tblRegPlayers1 where UserId='PL00011'", con);
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
ddlGender.Items.FindByText(rdr["Gender"].ToString()).Selected = true;
}
}
Now it doesnt throw any error and it doesnt select the value as well.
PS : 1.I have set Autopostback true for the ddl.
2.I am aware of sqlInjection and have made changes to make it look simpler.
My final PageLoad looks like this :
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//btnReset.Visible = false;
ExtractData();
BindDisabilityDropDown();
BindGenderDropDown();
BindStateDropDown();
}
if (hfImagePath.Value == "" || hfImagePath.Value == "0")
{
imgCropped.ImageUrl = "~/ProfilePictures/DefaultProfilePicture.png";
hfImagePath.Value = "0";
}
else
{
imgCropped.ImageUrl = "~/ProfilePictures/" + hfImagePath.Value;
}
//lblRegistration.Text = Session["Button"].ToString();
}
For one, you are calling ExtractData before you have actually bound the DropDownList in the BindGenderDropDown method. This means that your dropdown will have no items when you try to look it up and set the selected item. First things first you need to move the databinding code above ExtractData.
Second, you are you trying to set the selected value in an unusual way. Instead of attempting to FindByText you should try setting SelectedValue instead.
I will assume that the contents of rdr["Gender"] in ExtractData is the GenderId you have bound to the dropdown, and not the display value in GenderName. I will also assume that GenderId is M and F and GenderName is Male and Female (although if your actual implementation varies slightly then that's ok).
Try changing:
ddlGender.Items.FindByText(rdr["Gender"].ToString()).Selected = true;
To:
ddlGender.SelectedValue = rdr["Gender"].ToString();
Also be sure to remove the code you have added for the DataBound handler, it is not necessary here.
DataSet ds = new DataSet();
da.Fill(ds);
ddlGender.DataSource = ds;
ddlGender.DataTextField = "GenderName";
ddlGender.DataValueField = "GenderId";
ddlGender.DataBind();
You are trying to set the value to a specific Column, yet you are binding it to a DataSet and not a DataTable. (A DataSet has no columns only DataTables).
Try the following assuming the DataSet has a table returned and the column names match your table structure:
string strDesiredSelection = "Male";
DataSet ds = new DataSet();
da.Fill(ds);
ddlGender.DataSource = ds.Tables[0];
ddlGender.DataTextField = "GenderName";
ddlGender.DataValueField = "GenderId";
ddlGender.DataBind();
foreach(ListItem li in ddlGender.Items){
if(li.Value.Equals(strDesiredSelection)){
ddlGender.SelectedIndex = ddlGender.Items.IndexOf(li);
}
}

How to pass a Session to a DataTable?

In my asp project I need to write all Items form the list box into database table using TVP. I have listbox, stored procedure (passing TVP - Table Valued Parameters). The main problem is that passing DataTable is NULL, but the Session isn't. I'll send you my code form aspx.cs file (only one block, if you'll nedd more, let me know).
protected void ASPxButton1_Click(object sender, EventArgs e)
{
//DataTable dts = Session["SelectedOptions"] as DataTable;
DataTable _dt;
//_dt = new DataTable("Items");
_dt = Session["SelectedOptions"] as DataTable;
_dt.Columns.Add("Id", typeof(int));
_dt.Columns.Add("Name", typeof(string));
foreach (ListEditItem item in lbSelectedOptions.Items)
{
DataRow dr = _dt.NewRow();
dr["Id"] = item.Value;
dr["Name"] = item.Text;
}
SqlConnection con;
string conStr = ConfigurationManager.ConnectionStrings["TestConnectionString2"].ConnectionString;
con = new SqlConnection(conStr);
con.Open();
using (con)
{
SqlCommand sqlCmd = new SqlCommand("TestTVP", con);
sqlCmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = sqlCmd.Parameters.AddWithValue("#testtvp", _dt);
tvpParam.SqlDbType = SqlDbType.Structured;
sqlCmd.ExecuteNonQuery();
}
con.Close();
}
EDIT
Debugging Screenshot
You are not adding the new rows to the DataTable. You need something like this:
foreach (ListEditItem item in lbSelectedOptions.Items)
{
DataRow dr = _dt.NewRow();
dr["Id"] = item.Value;
dr["Name"] = item.Text;
_dt.Rows.Add(dr);
}
A secondary concern is where are you initialising Session["SelectedOptions"]? It appears that every time ASPxButton1 is clicked the code will try and add Id and Name columns to it, even if it already contains those two columns. It would seem more logical to do something like:
_dt = Session["SelectedOptions"] as DataTable;
if (_dt == null)
{
_dt = new DataTable("Items");
_dt.Columns.Add("Id", typeof(int));
_dt.Columns.Add("Name", typeof(string));
Session.Add("SelectedOptions", _dt);
}

i want to use data reader & update statement at same time

here is code
String[] month=new String[12]{"January","February","March","April","May","June","July","August","September","Octomber","November","December"};
int day = DateTime.Now.Day;
int mon= DateTime.Now.Month;
mon = mon - 1; //because month array is with 0
Label1.Text = day.ToString();
if (day==21)
{
int j = 1;
SqlCommand cmd1 = new SqlCommand();
cmd1.Connection = MyConn;
cmd1.CommandText = "SELECT No_of_times,Dustbin_no from mounthly_data";
SqlDataReader MyReader = cmd1.ExecuteReader();
while (MyReader.Read())
{
String a = MyReader["No_of_times"].ToString();
String b = MyReader["Dustbin_no"].ToString();
SqlCommand cmd = new SqlCommand();
cmd.Connection = MyConn;
cmd.CommandText = "update Yearly_data set [" + month[mon] + "]='"+a+"' where Dustbin_no='"+b+"'"; //just see ["+month[mon+"] it's imp
i = cmd.ExecuteNonQuery();
}
MyReader.Close();
}
i got error as
There is already an open DataReader associated with this Command which must be closed first.
I think you should give us the rest of the code above this code block because I'm not sure how a ExecuteNonQuery is using up a datareader. But from what I can gather, what you probably want is to open two separate connections. Only one datareader can be open per connection at a time. Either you use two separate connections or you could maybe use a datatable/dataset for the result of both your queries.
EDIT: From the rest of your code, yes, using two connections would be the simplest answer. When a reader is open, the connection associated with it is dedicated to the command that is used, thus no other command can use that connection.
I would recommend using a DataTable as this OLEDB example shows:
public static void TrySomethingLikeThis()
{
try
{
using (OleDbConnection con = new OleDbConnection())
{
con.ConnectionString = Users.GetConnectionString();
con.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM Customers";
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
foreach (DataRow row in dt.AsEnumerable())
{
cmd.CommandText = "UPDATE Customers SET CustomerName='Ronnie' WHERE ID = 4";
cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}

Invalid attempt to call Read when reader is closed

I'm kind of struggling trying to get this datagrid to bind. Everytime I run my code, I get an error message stating, "Invalid attempt to call Read when reader is closed". I don't see where I am closing my reader. Can you please help me? My code for loading the datagrid is below:
protected void LoadGrid()
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = ConfigurationManager.ConnectionStrings["VTC"].ConnectionString;
conn.Open();
string sql = "select * from roi_tracking";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
using (SqlDataReader sqlReader = cmd.ExecuteReader())
{
gridROI.DataSource = sqlReader;
gridROI.DataBind();
sqlReader.Dispose();
cmd.Dispose();
}
}
}
}
You can't use a SqlDataReader as a DataSource for a DataGrid.
From MSDN:
A data source must be a collection that implements either the
System.Collections.IEnumerable interface (such as
System.Data.DataView, System.Collections.ArrayList, or
System.Collections.Generic.List(Of T)) or the IListSource interface to
bind to a control derived from the BaseDataList class.
Datasource property:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.basedatalist.datasource.aspx
SqlDataReader:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx
A common methodology to bind the query results to your datagrid would be to use a SqlDataAdapter to fill a DataTable or DataSet and then bind that to your DataGrid.DataSource:
protected void LoadGrid()
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = ConfigurationManager.ConnectionStrings["VTC"].ConnectionString;
conn.Open();
string sql = "select * from roi_tracking";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = cmd;
adapter.Fill((DataTable)results);
gridROI.DataSource = results;
}
}
}
In addition to what pseudocoder said, you wouldn't want to bind to a SqlDataReader anyway: the connection to the database will remain open so long as the reader instance exists.
You definitely want to deserialize the data into some other disconnected data structure so that you release the connection back into the pool as quickly as possible.

Resources