Search code examples
asp.netentity-frameworkdatabound-controlsentitydatasourcenavigation-properties

How do I create a nested GridView bound to parent's EntityDataSource's navigation property?


<asp:FormView DataSourceId="edsAccounts">
    <ItemTemplate>
        <asp:TextBox Text='<%# Eval("Email") %>' />
        <asp:DataGrid ID="dgReports" DataSource='<%# Eval("Reports") %>'>
    </ItemTemplate>
</asp:FormView>
<asp:EntityDataSource ID="edsAccounts" runat="server" ConnectionString="name=Entities" DefaultContainerName="Entities" EntitySetName="Accounts" EntityTypeFilter="Account" Include="Reports" />

I want the dgReports to start working. Note that the email text box works just fine.


Solution

  • I indeed created seperate inner datasources, but I got another problem. I was unable to set the Where clause to the parent's Entity's ID.

    Notice that the FormView.DataItem is not accessible; it's of type EntityDataSourceWrapper which is a friend class and inaccessible.

    So I created a function to deal with it by reflection.

    I think it's a Microsoft bug, till they fix it, the following might be usefull to anyone who uses nested EntityDataSource controls.

    Here it is:

    Module Functions
        Public Function GetEntity(Of TEntity As EntityObject)(ByVal entityDataSourceWrapper As Object) As TEntity
            If entityDataSourceWrapper Is Nothing Then Return Nothing
            Dim type = entityDataSourceWrapper.GetType()
            If Not type.FullName = "System.Web.UI.WebControls.EntityDataSourceWrapper" Then Return Nothing
            Dim wrapper = type.GetProperty("WrappedEntity", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
            Return DirectCast(wrapper.GetValue(entityDataSourceWrapper, Nothing), TEntity)
        End Function
    End Module
    

    Now in the code behind I do the following:

    Protected Sub fvAccounts_DataBound(ByVal sender As Object, ByVal e As EventArgs) Handles fvAccounts.DataBound       
        If fvAccounts.CurrentMode <> FormViewMode.ReadOnly Then Exit Sub
        Dim account As Account = GetEntity(Of Account)(fvAccounts.DataItem)
        If account Is Nothing Then Exit Sub
        Dim edsReports As EntityDataSource = fvAccounts.Row.FindControl("edsReports")
        edsReports.Where = "it.Account.AccountId = " & account.AccountId
        gvReports.DataBind()
    End Sub
    

    Note the hierarchy in the model: Account has many reports.