Flattening an Entity Framework objectquery result with includes

2.3k Views Asked by At

I'm trying to get to grips with Entity Framework and there is one thing that's really tripping me up. It doesn't help that I'm still not totally sure of the terminology, and I'm trying to avoid learning LINQ at the same time, so googling is difficult.

I have two tables, company and addresses with a 1-to-many relationship. If I write the following:

ObjectQuery<Company> companies = queryContext.Companies.Include("Addresses");

It looks like I am getting what I want (companies -> Results View[0].Addresses.Count is > 0)

What I'd like to do now is bind the company names and all addresses to a gridview in an ASP.NET application

this.CompaniesGrid.DataSource = companies;
this.CompaniesGrid.DataBind();

<asp:GridView runat="server" ID="CompaniesGrid" AllowSorting="true">
    <Columns>
        <asp:BoundField DataField="Name" />
        <asp:BoundField DataField="Address" />
    </Columns>
</asp:GridView>

This on its own throws an error (A field or property with the name 'Address' was not found on the selected data source) - I think because companies -> Results View[0].Name exists but .Address doesn't (because it's buried in the Addresses relationship). Binding to Addresses.Address doesn't help either.

I found one really ugly workaround at the bottom of this thread but I would rather avoid it if possible.

Is there any way to 'flatten' my results so that the top level objects provide addess to all included fields?

Any help much appreciated!

2

There are 2 best solutions below

4
On BEST ANSWER

Your objectquery is returning a graph. While I think you really ought to suck it up and learn linq if you want to program in .NET (big grin ...except really, you should), you could write a projection query to bring back flattened results and bind those in ASP.NET.

The trick to flattening is to start with the "child" in the relationship.So something like this:

grid.datasource= context.Addresses.Select
          (a=>new {a.Company.CompanyName,a.Street, a.City}).ToList();

(code not guaranteed since the stackoverflow UI does not provide .net intellisense or compile time checking. sheesh. ).

3
On

I don't completely get why you find the solution to use a template field is ugly?

Bound fields can only be bound to regular properties. To bind to a navigational property you have to use a Template field.

So the code in the thread you mentioned solves your problem.

If you really find this ugly you could implement your own bound field and make it support nested bindings but I think using a template field is a nicer solution.