I am working on a nested repeater. My issue seems to be at the moment, that when I execute my SQL command that no data is returned to the data reader. Even when I run the exact same query (Copy and Pasted) into SQL Server.
My noteDrClient reader does not contain data, it does however know that there are 5 columns in the table. I have no idea what to do at this point or why no data is being passed into the data reader. Can anyone see an obvious problem?
SqlConnection con = new SqlConnection("Data Source=***;Initial Catalog=*;User ID=*;Password=*;Integrated Security=False;MultipleActiveResultSets=true;");
Above is my connection string. Please notice that I have Multiple Active Result Sets set to true. I did this because I kept getting errors about my data reader being open, even though it was closed.
protected void rptList_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if ((item.ItemType == ListItemType.Item) ||
(item.ItemType == ListItemType.AlternatingItem))
{
System.Data.Common.DbDataRecord rd = (System.Data.Common.DbDataRecord)e.Item.DataItem;
Repeater nestedRepeater = e.Item.FindControl("NotesRepeater") as Repeater;
string FID = rd[0].ToString();
using (cmd2 = new SqlCommand("SELECT * FROM notes WHERE FID = 1356;", con)) ;
SqlDataReader noteDrClient = cmd2.ExecuteReader(); //no data is being filled to the data reader... even though this command pulls data in SQL Server Management Studio.
if (noteDrClient.Read()) { //bind the repeater if there is data to bind
nestedRepeater.DataSource = noteDrClient;
nestedRepeater.DataBind();
}
noteDrClient.Close();
}
You're using statement is disposing the SqlCommand before you have a chance to use it. Additionally, you're attempting to bind to a DataReader. Get the results from the data reader into a collection of "Note" entities and bind to the collection instead.
using (SqlCommand cmd2 = new SqlCommand("SELECT * FROM notes WHERE FID = 1356;", con))
{
using(SqlDataReader noteDrClient = cmd2.ExecuteReader())
{
while (noteDrClient.Read())
{
Note n = new Note();
... get note from data reader
notes.Add(n); // add note to collection
}
}
}
// bind child
nestedRepeater.DataSource = notes;
nestedRepeater.DataBind();
Edit:
You might want to look into the DataAdapter - http://www.mikesdotnetting.com/Article/57/Displaying-One-To-Many-Relationships-with-Nested-Repeaters
I solved the problem by creating an additional connection string instead of reusing the same connection string I had been using for primary repeater. The Data is still not binding, but it does exist.
using (cmd2 = new SqlCommand("SELECT * FROM notes WHERE FID = 1356;", con2)) ;
I think the semicolon in your query may cause problems.
Try using quotation marks around the value like this:
SELECT * FROM notes WHERE FID = '1356;'
If the semicolon is not part of the value:
SELECT * FROM notes WHERE FID = '1356'
Related
I have a SQL query which supposed to return only ONE row from the business database. Based on this, I have written following sql script to get the data from the result set.
string query = #"select
ProdMaster.data_Id Id,
ProdMaster.data_name Name,
ProdMaster.data_countryname CountryName
from RM.Db
order by ProdMaster.data.FromDate desc"
SqlCommand command = new SqlCommand(query, conn);
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.Read())
{
countryname = reader["CountryName"].ToString();
}
}
But, there is some data issue in the database, sometimes it returns multiple rows.
How do we check the row count? If rows more than one we want to return a custom exception.
Note:
I do not want to use COUNT(*) in the query.
We don't have control on RM.Db database - it might have data issues (3rd party)
Don't you consider the next approach to solve your problem:
SqlCommand command = new SqlCommand(query, conn);
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.Read())
{
countryname = reader["CountryName"].ToString();
}
// Try to read the second row.
if (reader.Read())
{
// If we are inside this if-statement then it means that the query has returned more than one row.
// Here a custom exception must be thrown.
}
}
You can use SqlDataAdapter instead and fill the contents from the table in a dataset. The dataset will have a table inside it you can count the row like this - ds.Tables[0].Rows.Count
There can be problems related to Datareader as it is a stream of data and db can have changes while reading. A more thorough discussion on the same can be found on this thread -
How to get number of rows using SqlDataReader in C#
Hello everyone I am currently working on some testing project and I am having a little problem. Using selenium, I need to SendKey in specific element but instead of fixed value i need to use value (data) from my database. Can anyone help me with how to retrieve single value from database and store it in a variable so i can use it later.
Thank you and sorry for a noobish question - see code below:
SqlConnection conn = new SqlConnection();
SqlCommand command;
SqlDataReader dataReader;
conn.ConnectionString = "Server=******;Database=****;User ID=sqlserver;password=****;MultipleActiveResultSets=true;");
string query = "select RequestID, from AutomaticPayment where RequestID ='1230322'";
DataTable dt = new DataTable();
command = new SqlCommand(query, conn);
conn.Open();
dataReader = command.ExecuteReader();
dt.Load(dataReader);
driver.FindElement(By.Id("requestID")).SendKeys(VALUE FROM DATABASE);
You can use the following code
using (SqlConnection connection = new SqlConnection(_connectionString))
{
SqlDataAdapter sda = new SqlDataAdapter(query, connection);
connection.Open();
SqlCommand cmd = new SqlCommand(query, connection);
try
{
result = cmd.ExecuteScalar().ToString();
}
catch(NullReferenceException n)
{
result = "";
}
}
ExecuteScaler gets you the first column of the first row and additional columns are ignored. Use the value from result in your SendKeys()
Use conditions to limit the result:
Select data
SELECT TOP 1 RequestID FROM AutomaticPayment // Always returns 1 row
Or
SELECT RequestID FROM AutomaticPayment WHERE Id = 123 // Id must be unique to return 1 row
And maybe other ways.
Get value
var value = dt.Rows[0][1];
Or
var value = dt.Rows[0]["RequestID"];
From what i worked on with SqlCommand just do the following :
int yourId = 0;
dataReader = command.ExecuteReader()
while(dataReader.Read())
{
yourId = dataReader.GetInt32(0);
}
With that, you should have your value set to the first column of the dataReader. (that is selected thanks to your query, since you are requesting on a specific id, i guess it will return only one column
there is many other type available for Reader : Reader Microsoft Doc
And if you have in the futur many data to collect, use the ORM entity framework, work well for me
Source
EDIT :
Since you are only querying one data, maybe the solution of #work_ishaan is better than mine in this case, check it out.
Sorry for the large heading, I don't know what is going on with my code. I am pulling all serial numbers for a given work order number and status code and populating a list box with the results. My issue is, my code is pulling the number but listing it twice in the list box control. I am using a postgres database. Here is my code.
private void Get_Serial_Numbers()
{
NpgsqlConnection conn = Connection.getConnection();
try
{
conn.Open();
NpgsqlCommand cmd = new NpgsqlCommand("select product_serial_number from master_product where product_wo_number = :WorkOrder and status = :Status;", conn);
cmd.Parameters.Add(new NpgsqlParameter("WorkOrder", IdStorage.WorkOrderNumber));
cmd.Parameters.Add(new NpgsqlParameter("Status", 128));
NpgsqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
object serialNumber = dr["product_serial_number"];
lstProductsInWO.Items.Add(serialNumber.ToString());
}
if (lstProductsInWO.Items.Count == 0)
{
lstProductsInWO.Items.Add("No Data");
lblSerialInWO.Text = "Products in WO 0";
}
else
{
ProductTotal = lstProductsInWO.Items.Count;
lblSerialInWO.Text = "Products in WO " + ProductTotal.ToString();
}
dr.Close();
cmd.Dispose();
}
There are two possilities:
You accidently call the method Get_Serial_Numbers() twice in some event handlers - check it by debugging to make sure that the code runs only once.
You get the items twice from the table. Verify what the query returns (under the debugger) or running it manually against the database.
If I'm using a parameterized query (ASP.NET with C#) in SQL, such as
var db = Database.Open("Database1");
SqlCommand cmd = new SqlCommand("SELECT * FROM pageinfo WHERE pageID = #pageID");
cmd.Parameters.AddWithValue("#pageID", 1);
And later on in the page, I want to do a foreach loop of whatever data was retrieved:
foreach(var row in ???)
What would I use (in place of the ???) to access the data I just retrieved?
Thanks.
It depends on how you execute a query.
Usually it's done by SqlCommand.ExecuteReader
For example, in your case, you can:
....
SqlDataReader reader = cmd .ExecuteReader();
while (reader.Read())
{
...
}
But there are also other ways to rertieve the data, for example using DataSet
For a complete example on how to do that can have a look on:
Using ADO.NET for beginners
You can use while iteration statement with SqlCommand.ExecuteReader instead of foreach. Take a look this;
var db = Database.Open("Database1");
SqlCommand cmd = new SqlCommand("SELECT * FROM pageinfo WHERE pageID = #pageID");
cmd.Parameters.AddWithValue("#pageID", 1);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader[0]);
}
reader[0] returns first row of first column and reader[1] returns first row of second column if your data has of course.
I'm running some code in Page_Load then I store the results from this code in some local variables.
Now I use this local variables to assign them to the controls inside my repeater item template
The Problem Is >> the page doesn't displays the item template but there's no data bound to it..I think the repeater can't load the data assigned to it in the Page_Load and it get's initialized -life cycle related issues-
Any idea what the problem is exactly ? and how to solve this ?
EDIT
Some example code :
public partial class MyPage: System.Web.UI.Page
{
int UserId = 0;
protected void Page_Load(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDbConn"].ConnectionString);
SqlCommand comm = new SqlCommand("SELECT * From Users, conn);
SqlDataReader reader;
conn.Open();
reader = comm.ExecuteReader();
//I'm not sure if I need those two lines:
AllBrandsRptr.DataSource = reader;
AllBrandsRptr.DataBind();
while (reader.Read())
{
UserId = (int)reader["UserId"];
}
conn.Close();
}
}
protected void AllBrandsRptr_ItemCommand(object source, RepeaterCommandEventArgs e)
{
Label LabelTest = (Label)e.Item.FindControl("MyTestLabel");
LabelTest.Text = UserId.ToString();
}
EDIT 2
My Sql SELECT Statement
string command1 = "SELECT Brands.BrandId, Brands.BrandName, Brands.BrandLogo, Brands.BrandWebsite, Brands.IsBrandVisible, Cuisines.CuisineType, VenueTypes.VenueTypeName FROM Brands FULL OUTER JOIN BrandCuisines ON BrandCuisines.BrandId = Brands.BrandId FULL OUTER JOIN Cuisines ON Cuisines.CuisineId = BrandCuisines.CuisineId FULL OUTER JOIN BrandVenueTypes ON BrandVenueTypes.BrandId = Brands.BrandId FULL OUTER JOIN VenueTypes ON VenueTypes.VenueTypeId = BrandVenueTypes.VenueTypeId";
My Filtration Code
conn.Open();
reader = comm.ExecuteReader();
AllBrandsRptr.DataSource = reader;
AllBrandsRptr.DataBind();
while (reader.Read())
{
if (((int)reader["BrandId"]) == BrandId) //this line to pass collecting some info, if I already iterated through the same Id
{
BrandId = (int)reader["BrandId"];
BrandName = (string)reader["BrandName"];
BrandLogo = (string)reader["BrandLogo"];
BrandWebsite = (string)reader["BrandWebsite"];
IsVisible = (bool)reader["IsBrandVisible"];
}
if (reader["CuisineType"] != DBNull.Value)
{
Cuisines += (string)reader["CuisineType"];
}
if (reader["VenueTypeName"] != DBNull.Value)
{
VenueTypes += ", " + (string)reader["VenueTypeName"];
}
conn.Close();
My Initial Problem
How to use in my application a SELECT statement that must return more than one record to show multiple values for a certain field (m:m relation)
You shouldn't manually iterate over the DataReader at all. It is a forward-only tool. Only the Repeater or your while loop may iterate through the results. I believe your immediate problem is that your while loop is exhausting the DataReader before the Repeater renders.
When you call DataBind(), you're instructing the Repeater to render its template for every item in the collection you assigned as its DataSource. So, any filtration would need to happen before. Ideally, you should probably add that filtration logic as a where clause to your SQL statement.
Can you be more specific about the real problem you're trying to solve? It's hard to give you accurate advice otherwise.
Update:
Keep in mind that while(reader.Read()) does not work like an event handler or otherwise similar to how it might semantically sound. In other words, you aren't telling the program to do something when the DataReader is read, you're telling it to start reading through the data immediately (unrelated to the Repeater).
Here's what I suggest you try:
string sql = "Your current SQL here";
string connectionString = "Your connection string here";
// The using block ensures that the connection will be closed and freed up,
// even if an unhandled exception occurs inside the block.
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
AllBrandsRptr.DataSource = dt;
AllBrandsRptr.DataBind();
var cuisineTypes = from row in dt.AsEnumerable()
select row["CuisineType"];
string cuisines = string.Join(", ", cuisineTypes.Distinct());
var venueTypes = from row in dt.AsEnumerable()
select row["VenueTypeName"];
string venues = string.Join(", ", venueTypes.Distinct());
}
By using a DataTable instead of DataReader, you're able to iterate through the data as many times as necessary. The DataReader is more performant, if a single, forward-only read through the data is all you need, but the DataTable is much more powerful and is helpful in these situations beyond the DataReader's capabilities.
It's worth mentioning that if you care about this project in the long-term and want to make it maintainable, you should consider eventually moving some of this data access code to a separate layer. You should strive to never have SQL statements or direct data access code in your .aspx.cs files.
Then, your code in Page_Load could be strongly typed and easier to work with:
List<Brand> brands = Brand.GetAllBrands();
AllBrandsRptr.DataSource = brands;
AllBrandsRptr.DataBind();
var cuisineTypes = from brand in brands
select brand.CuisineType;
string cuisines = string.join(", ", cuisineTypes.Distinct());
var venueTypes = from brand in brands
select brand.VenueType;
string venues = string.join(", ", venueTypes.Distinct());