I am trying to figure out how to bind a nested collection that I have retrieved using EF into either an asp:ListView or asp:Repeater control for a web form.
Using EF I created the following query where I am selecting a group of agencies and a list of the entities they are sharing with other agencies.
public static ICollection<Agency> GetAllAgencies()
{
ICollection<Agency> retAgencies = null;
try
{
using (var context = new InformSecurityEntities(string.Empty))
{
// retAgencies = context.Agencies.OrderBy(a => a.AgencyName).ToList();
retAgencies = (from a in context.Agencies
.Include("SecurityDataShares1")
.OrderBy(a => a.AgencyName)
select a).ToList();
}
}
catch (Exception ex)
{
throw new Exception("Exception thrown in UserFactory.GetAllAgencies() : " + ex.InnerException + ex.Message);
}
return retAgencies;
}
I’ve been testing this in a console app and it works fine. Within the console I was rendering my results as follows:
private static void showAgencies()
{
var results = UserFactory.GetAllAgencies();
foreach (var item in results)
{
Console.WriteLine("Id: {0} || Name: {1}",
item.AgencyId,
item.AgencyName);
foreach (var i in item.SecurityDataShares1)
{
Console.WriteLine(i.ReceivingAgency.AgencyName);
Console.WriteLine(convertEntityToText(i.EntityId));
}
}
Console.WriteLine("enter...");
Console.ReadLine();
}
Note: SecurityDataShares1 is an ICollection
What I would like to be able to do is take the results and render them into a format similar to below within a webform:
Agency 1
Entity 1, Entity 2, Entity 3 ...
Agency 2
Entity 1, Entity 4, Entity 5 ...
Where I am getting hung up is in the console app I could access the nested collection and iterate over it to render out my results. I have tried using a repeater control with a secondary nested repeater and binding the control to the method results.
<asp:Repeater ID="agencyListRepeater" runat="server" OnItemDataBound="mainRepeaterBound">
<ItemTemplate>
<div class="itemsRow">
<div class="column-holder">
<asp:Label CssClass="mgmtResultText" ID="lbl_AgencyName" runat="server" Text='<%# Eval("AgencyName") %>' /></div>
<br />
<div class="mgmtIndentDiv">Sharing data with the following agencies:</div>
<asp:Repeater id="nestedDataShare" runat="server">
<ItemTemplate>
<asp:Label runat="server" Text='<%# Eval("SecurityDataShares1.AgencyName") %>' />
<asp:Label runat="server" Text='<%# Eval("SecurityDataShares1.EntityId") %>' />
</ItemTemplate>
</asp:Repeater>
</div>
</ItemTemplate>
</asp:Repeater>
Code behind
if (userRole.IsSysAdmin)
{
var agencyData = UserFactory.GetAllAgencies();
if (agencyData != null || agencyData.Count > 0)
{
agencyListRepeater.DataSource = agencyData;
agencyListRepeater.DataBind();
}
else
...
However this would fail whenever SecurityDataShares1 was null.
Any suggestions or a best approach for this?
Thanks in advance.
I was never able to get the nested reader to render data, while it would compile, zero (0) results were always returned on the nested objects. As a result I looked to an alternate solution. Bear in mind this is more of a work around to the original questionfor rendering the data within the UI.
Instead of using a data reader I decided to try injecting html directly into the ui using the LiteralControl class. To do this within the aspx page I added a panel control. You could also use a div element with the attribute ruant=”server” but I decided to use the
<asp:Panel/>control:So within the ASPX file I added the following:
Then within my code behind I created a method with two parameters p = PanelName and a = Collection.
This approach then allowed me to iterate through the collection and write out to the UI the results as html. Remember LiteralControl only allows the creation of html elements or strings that do not require serverside processing. So if you want to add server side controls you will need to use a separate method for the creation of the object Look here for an example
This is then called in a format such as:
I’d still appreciate any alternative ideas or approaches otherwise I Hope this helps.
-cheers!