Question

I'm stumbling upon a small issue when retrieving a set of data with Entity Framework 5 Code First. Here's my code:

var data = context.Customers
            .Include("Orders")
            .Include("Orders.Items")
            .Include("Orders.Items.Article").ToArray();
foreach (var customer in data)
{
    customer.Orders = customer.Orders.OrderByDescending(o => o.OrderDate).ToArray();
}

This works (whoo!). But, I'm trying to get that foreach out of there, I want the database engine to remain responsible for processing data. How do I do this?

I've tried this type of join:

var data = from customer
           in context.Customers
           select new {
               customer.Id,
               customer.Name,
               // customer.Orders below doesn't have an Include() to include order items
               Orders = customer.Orders.OrderByDescending(b => b.OrderDate)
           };

// Translate anonymous object to actual models
var customers = new List<CustomerModel>();
foreach (var customer in data)
{
    customers.Add(new CustomerModel()
    {
        Id = customer.Id,
        Name = customer.Name,
        Orders = customer.Orders.ToArray()
    });
}

But, as the comment says, customer.Orders doesn't have an Include() method to include items and articles belonging to those items. I then tried to get in from the context instead of the customer object:

Orders = context.Orders.Include("Items").Where(o => o.Id == customer.Id)

But this results in a runtime exception that Include() cannot be used this way (in nested queries?):

Method 'System.Data.Entity.Infrastructure.DbQuery`1[MyTests.Models.OrderModel] Include(System.String)' declared on type 'System.Data.Entity.Infrastructure.DbQuery`1[MyTests.Models.OrderModel]' cannot be called with instance of type 'System.Data.Objects.ObjectQuery`1[MyTests.Models.OrdersModel]'

Is something like that even possible, nesting it out like that?

How do I make the database process the data instead of using a foreach in my first code block?

Thanks in advance.

JP

Was it helpful?

Solution

You can try this query:

List<CustomerModel> customers =
           (from customer
            in context.Customers
            select new {
                customer.Id,
                customer.Name,
                Orders = customer.Orders
                    .OrderByDescending(o => o.OrderDate)
                    .Select(o => new {
                        Order = o,
                        Items = o.Items
                            .Select(i => new {
                                Item = i,
                                Article = i.Article
                            })
                    })
           })
           .AsEnumerable()
           .Select(x => new CustomerModel
           {
               Id = x.Id,
               Name = x.Name,
               Orders = x.Orders.Select(o => o.Order).ToArray()
           })
           .ToList();

Although Item and Article in the inner anonymous object are not used they will be loaded and Entity Framework's relationship fixup should set the correct navigation properties for Order.Items and Item.Article - as long as the relationships are not many-to-many and you don't use AsNoTracking.

If you want to perform this as a no-tracking query, you basically have to set the navigation properties yourself. It should be possible by moving the following additional Select between AsEnumerable() and Select(...):

           // .AsEnumerable()
           .Select(x => new {
               Id = x.Id,
               Name = x.Name,
               Orders = x.Orders.Select(y => {
                   y.Order.Items = y.Items.Select(z => {
                       z.Item.Article = z.Article;
                       return z.Item;
                   }).ToArray();
                   return y;
               })
           })
           // .Select(x => new CustomerModel ...

OTHER TIPS

This should work for you:

var os = new DbContext().Orders;

var data = from customer
       in context.Customers
       select new {
           customer.Id,
           customer.Name,

           Orders = os.Include("Items").Include("Items.Article")
               .Where(o => o.CustomerId == id)
               .OrderByDescending(b => b.DatumAangemaakt)
       };
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top