Sometimes I miss the option that you have in classic ASP, PHP or Ruby on Rails to just put a nested loop into the html page (view, presentation layer) to display nested data. Of course this is, strictly speaking, against ASP.NET best practices where you’re supposed to use web controls for everything. Then again one could make the argument that the loop actually belongs in the view. This would be .aspx page, and not in the controller or the model (code behind file in ASP.NET).
The task at hand is to iterate through parent categories and child items. The technique suggested by Microsoft is outlined here, and this article uses a nested repeater with a self-join. Starting point is the following DataSet with two related tables and a repeater in the page:
DataSet myDS = new DataSet("NestedRepeaterDemo");
… //fill the dataset
myDS.Tables[0].TableName = "ParentCategories";
myDS.Tables[1].TableName = "ChildItems";
DataRelation relation = new DataRelation("myRelation",
myDS.Tables["ParentCategories"].Columns["CatID"],
myDS.Tables["ChildItems"].Columns["CatID"], true);
relation.Nested = true;
myDS.Relations.Add(relation);
parentRepeater.DataSource = myDS;
parentRepeater.DataBind();
So why not bind the child repeater in the page, just for the heck of it:
<table>
<asp:Repeater id="parentRepeater" runat="server">
<itemtemplate>
<tr class="categoryInTable">
<td colspan="2">
<%# DataBinder.Eval(Container.DataItem, "CategoryName") %>
</td>
</tr>
<asp:Repeater ID="childRepeater" runat="server" datasource=’<%# ((DataRowView)Container.DataItem).Row.GetChildRows("myRelation") %>‘ >
<ItemTemplate>
<tr><td>
<%# Eval("ItemName")%>
</td>
<td>
<%# Eval("ItemDescription")%>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</itemtemplate>
</asp:Repeater>
</table>
Sure enough with this code you will run into a DataBinding: ‘System.Data.DataRow’ does not contain a property with the name x error.
As a quick explanation for this error the following might suffice:
When the nested repeater binds to its datasource calling the GetChildRows command of the parent DataRowView.Row object the latter returns an array of DataRows (the “child rows”, an object of type DataRow[]) which each repeater Item will be bound to now. However, Eval with the above syntax will only bind to named fields of a DataView object that exposes a name property for each field. The DataRow returned by GetChildRows is merely a row in a table without the name properties so that each field can be accessed only with an indexer (DataRow["ItemName"]).
This is why you can either change the binding expressions above like so:
<td>
<%# Eval("[\"ItemName\"]")%>
</td>
<td>
<%# Eval("[\"ItemDescription\"]")%>
</td>
or you can change the datasource to use the CreateChildView of the DataRowView directly like this:
<asp:Repeater ID=”childRepeater” runat=”server” datasource=’<%# ((DataRowView)Container.DataItem).CreateChildView(”myRelation”) %>’ >
and use old data binding syntax <%# Eval (”ItemName”) %> because now you have a DataView again (just like in the parentRepeater) which supports binding to the data field by name. Of course you have the option to do all the databinding in the code-behind file (usually the ItemDataBound event of each repeater) which gives you better debugging support than the approach above.
I find this “nested data” stuff overly complicated in ASP.NET, especially compared with how easy it is with Ruby on Rails. The plethora of objects which each behave differently is difficult to work with and the Repeater itself is limited in its built-in functionality and designer-support.
Sure enough I also ran into the
Compiler Error Message: CS0246: The type or namespace
name ‘DataRowView’ could not be found (are you missing a
using directive or an assembly reference?)
which IMHO is clearly a bug in ASP.NET as a reference to System.Data exists in the code-behind file that the .aspx web form inherits from. This issue can be fixed by either having an <%@ Import Namespace=”System.Data” %> tag in your aspx file or declaring DataRowView with the full namespace System.Data.DataRowView in the page each time.
For an in-depth view of the binding issues see this article. You might also find this post helpful.
Recent Comments