The Page Page_Load Event Vs The Repeater ItemCommand - c#

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());

Related

How can i search SQL Server Database while typing in C# Winforms application?

I am showing some sql table results in data grid view in winforms app. I normally use DbEntities but i had to use join in my query to get results from multiple results, so instead i used this code.
And i want to add a query and a textbox to search results while typing. How can i do that from what i already started?
SqlConnection con = new SqlConnection("server=.; Initial
Catalog=winforms;Integrated Security=SSPI");
DataTable dt = new DataTable();
string sql = "SELECT Personel.ad, Personel.soyad, Personel.tc, Personel.dogum, Personel.isgiris, Birim.birimad AS [Birim], Sube.subead AS [Şube] FROM Personel JOIN Birim ON Birim.birimid = Personel.birimid JOIN Sube ON Sube.subeid = Personel.subeid";
con.Open();
SqlDataAdapter da = new SqlDataAdapter(sql, con);
da.Fill(dt);
dataGridView1.DataSource = dt;
Found this answer to search in DataTable.
So for your solution you would need to implement
public static DataTable SearchInAllColums(this DataTable table, string keyword, StringComparison comparison)
{
if(keyword.Equals(""))
{
return table;
}
DataRow[] filteredRows = table.Rows
.Cast<DataRow>()
.Where(r => r.ItemArray.Any(
c => c.ToString().IndexOf(keyword, comparison) >= 0))
.ToArray();
if (filteredRows.Length == 0)
{
DataTable dtProcessesTemp = table.Clone();
dtProcessesTemp.Clear();
return dtProcessesTemp;
}
else
{
return filteredRows.CopyToDataTable();
}
}
And then you could use it in your changeevent:
void textBox1_TextChanged(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("server=.; Initial
Catalog=winforms;Integrated Security=SSPI");
DataTable dt = new DataTable();
string sql = "SELECT Personel.ad, Personel.soyad, Personel.tc, Personel.dogum, Personel.isgiris, Birim.birimad AS [Birim], Sube.subead AS [Şube] FROM Personel JOIN Birim ON Birim.birimid = Personel.birimid JOIN Sube ON Sube.subeid = Personel.subeid";
con.Open();
SqlDataAdapter da = new SqlDataAdapter(sql, con);
da.Fill(dt);
dataTable.SearchInAllColums(textBox1.Text, StringComparison.OrdinalIgnoreCase);
dataGridView1.DataSource = dataTable;
}
HOWEVER: Doing it like this will cause alot of traffic to your sql server. I would strongly suggest you to also implement some form of cache here for getting all searchable data. If that's an option.
You can use TextChanged event for textbox and send the text to the function as parameter. Then add the text to the WHERE clause on SQL query.
Be careful about user inputs for querying SQL. This is just an example, not very safe.
void textBox1_TextChanged(object sender, EventArgs e)
{
CallSQL(textBox1.Text);
}
void CallSQL(string filterText)
{
...
...
string sql = string.Format("SELECT ... WHERE Personel.Ad = {0}", filterText);
...
...
}
just o add to the question and futures similiar problems:
Do not use SQL as "insta-search" on textchanged proprieties. Its bad for many reasons as people mentioned above. But first of all, you can have problems by locking up SQL tables for having people trying so search something and generating alot of traffic as consequence, and even for one user, its unsafe and unfriendly to resources.. Besides, you have a high traffic for SQL injection. There are some good programming practices to make it safer, i'll try to elucidate a little more.
Okay, you already know this piece of information. But how the Correct way to do it?
Use objects, DAL and cache info until its old enough and have to update it.
How:
First things first, you should create a DAL/DAO class that is used ONLY for sql querys and operations. Do some search on the subject and why is a bad idea to have your business rules and sql code scrambled togheter. Here some short text about it:About DAL/DAO
Then, create a class of objects. For example: PersonelInfo. Wich contains every attribute that you need, like: name,documents, etc.
Here some info about objects handling: Using Objects with C#
After having your object nice and done, use lists to store and pass it to datatable or directly to datagridview if you wich.
List<Objectname> listname = new List<Objectname>();
Then, use some loop to iterate through SQL data and fill your list.
Example:
while(dataReader.Read())
{
Object objectname = new Object();
objectname.attribute1 = dataReadet["columname"].ToString();
objectname.attribute2 = dataReadet["columname"].ToString();
objectname.attribute3 = dataReadet["columname"].ToString();
listname.Add(objectname);
}
at the end return your objectlist:
Return listname;
That way you have full organized object list that you can:
Use as base for cache. That list contains all information that user
needs to search for. Search the list with a foreach loop and return
desired values to the user. Just remember to update it when it gets
old.
Use it as source for Datagridview or Datatable, its cheap.
Use it with JSON, it can be sent by API or simple UDP/TCP connection
Hope this short comment bring you some light with data handling.
Note that not every data is safe to keep that way. Passwords and protected stuff should not be stored in memory or other ways that can be exploited.

Update or delete current row of database results

I'm trying to port some old VB6 code to C# and .NET.
There are a number of places where the old code uses a RecordSet to execute a SQL query and then loop through the results. No problem so far, but inside the loop the code makes changes to the current row, updating columns and even deleting the current row altogether.
In .NET, I can easily use a SqlDataReader to loop through SQL query results, but updates are not supported.
So I've been playing with using a SqlDataAdapter to populate a DataSet, and then loop through the rows in a DataSet table. But the DataSet doesn't seem very smart compared to the VB6's old RecordSet. For one thing, I need to provide update queries for each type of edit I have. Another concern is that a DataSet seems to hold everything in memory at once, which might be a problem if there are many results.
What is the best way to duplicate this behavior in .NET? The code below shows what I have so far. Is this the best approach, or is there another option?
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet dataset = new DataSet();
using (SqlDataAdapter adapter = new SqlDataAdapter(new SqlCommand(query, connection)))
{
adapter.Fill(dataset);
DataTable table = dataset.Tables[0];
foreach (DataRow row in table.Rows)
{
if ((int)row["Id"] == 4)
{
if ((int)row["Value1"] > 0)
row["Value2"] = 12345;
else
row["Value3"] = 12345;
}
else if ((int)row["Id"] == 5)
{
row.Delete();
}
}
// TODO:
adapter.UpdateCommand = new SqlCommand("?", connection);
adapter.DeleteCommand = new SqlCommand("?", connection);
adapter.Update(table);
}
}
Note: I'm new to the company and can't very well tell them they have to change their connection strings or must switch to Entity Framework, which would be my choice. I'm really looking for a code-only solution.
ADO.NET DataTable and DataAdapter provide the closest equivalent of ADO Recordset with applies separation of concens principle. DataTable contains the data and provides the change tracking information (similar to EF internal entity tracking) while DataAdapter provides a standard way to populate it from database (Fill method) and apply changes back to the database (Update method).
With that being said, what are you doing is the intended way to port the ADO Recordset to ADO.NET. The only thing you've missed is that you are not always required to specify Insert, Update and Delete commands. As soon as your query is querying a single table (which I think was a requirement to get updateable Recordset anyway), you can use another ADO.NET player called DbCommandBuilder:
Automatically generates single-table commands used to reconcile changes made to a DataSet with the associated database.
Every database provider provides implementation of this abstract class. The MSDN example for SqlCommandBuilder is almost identical to your sample, so all you need before calling Update is (a bit counterintuitive):
var builder = new SqlCommandBuilder(adapter);
and that's it.
Behind the scenes,
The DbCommandBuilder registers itself as a listener for RowUpdating events that are generated by the DbDataAdapter specified in this property.
and dynamically generates the commands if they are not specifically set in the data adapter by you.
I came up with an (untested) solution for a data table.
It does require you to do some work, but it should generate update and delete commands for each row you change or delete automatically, by hooking up to the RowChanged and RowDeleted events of the DataTable.
Each row will get it's own command, equivalent to ADODB.RecordSet update / delete methods.
However, unlike the ADODB.RecordSet methods, this class will not change the underling database, but only create the SqlCommands to do it. Of course, you can change it to simply execute them on once they are created, but as I said, I didn't test it so I'll leave that up to you if you want to do it. However, please note I'm not sure how the RowChanged event will behave for multiple changes to the same row. Worst case it will be fired for each change in the row.
The class constructor takes three arguments:
The instance of the DataTable class you are working with.
A Dictionary<string, SqlDbType> that provides mapping between column names and SqlDataTypes
An optional string to represent table name. If omitted, the TableName property of the DataTable will be used.
Once you have the mapping dictionary, all you have to do is instantiate the CommandGenerator class and iterate the rows in the data table just like in the question. From that point forward everything is automated.
Once you completed your iteration, all you have to do is get the sql commands from the Commands property, and run them.
public class CommandGenerator
{
private Dictionary<string, SqlDbType> _columnToDbType;
private string _tableName;
private List<SqlCommand> _commands;
public CommandGenerator(DataTable table, Dictionary<string, SqlDbType> columnToDbType, string tableName = null)
{
_commands = new List<SqlCommand>();
_columnToDbType = columnToDbType;
_tableName = (string.IsNullOrEmpty(tableName)) ? tableName : table.TableName;
table.RowDeleted += table_RowDeleted;
table.RowChanged += table_RowChanged;
}
public IEnumerable<SqlCommand> Commands { get { return _commands; } }
private void table_RowChanged(object sender, DataRowChangeEventArgs e)
{
_commands.Add(GenerateDelete(e.Row));
}
private void table_RowDeleted(object sender, DataRowChangeEventArgs e)
{
_commands.Add(GenerateDelete(e.Row));
}
private SqlCommand GenerateUpdate(DataRow row)
{
var table = row.Table;
var cmd = new SqlCommand();
var sb = new StringBuilder();
sb.Append("UPDATE ").Append(_tableName).Append(" SET ");
var valueColumns = table.Columns.OfType<DataColumn>().Where(c => !table.PrimaryKey.Contains(c));
AppendColumns(cmd, sb, valueColumns, row);
sb.Append(" WHERE ");
AppendColumns(cmd, sb, table.PrimaryKey, row);
cmd.CommandText = sb.ToString();
return cmd;
}
private SqlCommand GenerateDelete(DataRow row)
{
var table = row.Table;
var cmd = new SqlCommand();
var sb = new StringBuilder();
sb.Append("DELETE FROM ").Append(_tableName).Append(" WHERE ");
AppendColumns(cmd, sb, table.PrimaryKey, row);
cmd.CommandText = sb.ToString();
return cmd;
}
private void AppendColumns(SqlCommand cmd, StringBuilder sb, IEnumerable<DataColumn> columns, DataRow row)
{
foreach (var column in columns)
{
sb.Append(column.ColumnName).Append(" = #").AppendLine(column.ColumnName);
cmd.Parameters.Add("#" + column.ColumnName, _columnToDbType[column.ColumnName]).Value = row[column];
}
}
}
As I wrote, this is completely untested, but I think it should be enough to at least show the general idea.
Your constraints:
Not using Entity Framework
DataSet seems to hold everything in memory at once, which might be a
problem if there are many results.
a code-only solution ( no external libraries)
Plus
The maximum number of rows that a DataTable can store is 16,777,216
row MSDN
To get high performance
//the main class to update/delete sql batches without using DataSet/DataTable.
public class SqlBatchUpdate
{
string ConnectionString { get; set; }
public SqlBatchUpdate(string connstring)
{
ConnectionString = connstring;
}
public int RunSql(string sql)
{
using (SqlConnection con = new SqlConnection(ConnectionString))
using (SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.CommandType = CommandType.Text;
con.Open();
int rowsAffected = cmd.ExecuteNonQuery();
return rowsAffected;
}
}
}
//------------------------
// using the class to run a predefined patches
public class SqlBatchUpdateDemo
{
private string connstring = "myconnstring";
//run batches in sequence
public void RunBatchesInSequence()
{
var sqlBatchUpdate = new SqlBatchUpdate(connstring);
//batch1
var sql1 = #"update mytable set value2 =1234 where id =4 and Value1>0;";
var nrows = sqlBatchUpdate.RunSql(sql1);
Console.WriteLine("batch1: {0}", nrows);
//batch2
var sql2 = #"update mytable set value3 =1234 where id =4 and Value1 =0";
nrows = sqlBatchUpdate.RunSql(sql2);
Console.WriteLine("batch2: {0}", nrows);
//batch3
var sql3 = #"delete from mytable where id =5;";
nrows = sqlBatchUpdate.RunSql(sql3);
Console.WriteLine("batch3: {0}", nrows);
}
// Alternative: you can run all batches as one
public void RunAllBatches()
{
var sqlBatchUpdate = new SqlBatchUpdate(connstring );
StringBuilder sb = new StringBuilder();
var sql1 = #"update mytable set value2 =1234 where id =4 and Value1>0;";
sb.AppendLine(sql1);
//batch2
var sql2 = #"update mytable set value3 =1234 where id =4 and Value1 =0";
sb.AppendLine(sql2);
//batch3
var sql3 = #"delete from mytable where id =5;";
sb.AppendLine(sql3);
//run all batches
var nrows = c.RunSql(sb.ToString());
Console.WriteLine("all patches: {0}", nrows);
}
}
I simulated that solution and it's working fine with a high performance because all updates /delete run as batch.

Listing a number twice in a list box when pulling data from a database using the and key word in the sql statment in C#

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.

Populating a dropdown list from database

I have a asp.net page listing products (pulled from a database) with edit/delete buttons. The user can edit the product by clicking the edit button. I've been able to pull in data from the db to the textboxes based on the product selected. However, I am getting duplicate items in the dropdown box. It's only supposed to have 32 items and has 160 items (each item is appearing 5 times). I've used Items.Clear() but am still getting duplicates. Also the dropbox just shows the first item in the list rather than the appropriate item for that product that is currently in the db. Can anyone see what I may be doing wrong?
Thanks.
protected void Page_Load(object sender, EventArgs e)
{
this.Master.HighlightNavItem("Products");
string Mode = (Request.QueryString["Mode"]);
//Upon opening page, if this is an edit to existing product (populate product data)
if (Mode == "E")
{
if (!IsPostBack)
{
int ProductID = Int32.Parse(Request.QueryString["ID"]);
//Declare the connection object
SqlConnection Conn = new SqlConnection();
Conn.ConnectionString = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
//Connect to the db
Conn.Open();
//Define the query
//string sql = "SELECT dbo.Vendor.VendorName, dbo.Vendor.VendorID, dbo.Product.ProductName, dbo.Product.ProductNumber, dbo.lu_Category.CategoryID, dbo.lu_Category.Description FROM dbo.Product INNER JOIN dbo.Vendor ON dbo.Product.VendorID = dbo.Vendor.VendorID INNER JOIN dbo.lu_Category ON dbo.Product.CategoryID = dbo.lu_Category.CategoryID WHERE ProductID=#ProductID";
string sql = "SELECT ProductName, ProductNumber, ProductDescription, Cost, Markup, Unit, QtyOnHand, ShippingWeight, dbo.Vendor.VendorID, VendorName, dbo.lu_Category.CategoryID, Description FROM Vendor, Product, lu_Category WHERE ProductID=#ProductID";
//Declare the Command
SqlCommand cmd = new SqlCommand(sql, Conn);
//Add the parameters needed for the SQL query
cmd.Parameters.AddWithValue("#ProductID", ProductID);
//Declare the DataReader
SqlDataReader dr = null;
//Fill the DataReader
dr = cmd.ExecuteReader();
//Loop through the DataReader
ddlVendor.Items.Clear();
while (dr.Read())
{
txtProductName.Text = dr["ProductName"].ToString();
txtProductNo.Text = dr["ProductNumber"].ToString();
txtDescription.Text = dr["ProductDescription"].ToString();
txtCost.Text = dr["Cost"].ToString();
txtMarkup.Text = dr["Markup"].ToString();
txtUnit.Text = dr["Unit"].ToString();
txtQty.Text = dr["QtyOnHand"].ToString();
txtWeight.Text = dr["ShippingWeight"].ToString();
ListItem li = new ListItem();
li.Text = dr["VendorName"].ToString();
li.Value = dr["VendorID"].ToString();
ddlVendor.Items.Add(li);
You should change your SQL query and remove the , type of joins.
Then test your query directly in your database to make sure you don't get doubles.
The rest of your code looks fine so i'm sure testing your query will solve your problem.
Do not use Comma Joins it's deprecated.
I think you should have used inner or outer join to get your data. With ',' separated joins you are receiving data from both tables. like 32 rows of one table are getting appneded with 5 rows of other table.

SQL Command not filling data reader

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'

Categories

Resources