Tod
Tod

Reputation: 8242

How do I eager load a grandparent record in EF 4.1

I'm using EF4.1 and trying to understand the proper approach to take for eager loading. I have an order entry system with a Vendor (grandparent),Purchase Order (parent) and PO2Item (child) table. The model looks like this ModelScreenImage

I want to start with a PO2Item record and load the vendor. I thought I could just use .Include() like this:

var po = (from item in context.PO2Item.Include("PurchaseOrder.Vendor").AsNoTracking()
            where item.OrderLineItemId == lineItem.CostSourceLineItemId
            select item.PurchaseOrder).FirstOrDefault();

This does load the PurchaseOrder record but po.Vendor is null. I was reading Julia Lerman's book and Chapter 4 indicated I could use Load but I think 4.1 must have changed this from 4.0 because Load doesn't appear to be defined and there is no such thing as VendorReference. Eventually I dug into the ObjectContext and was able to do this:

   if (po!=null)
   {
       context.GetObjectContext().LoadProperty(po, "Vendor");  
   }

which does load the Vendor but I have the feeling I'm missing something much simpler. Why doesn't Include("PurchaseOrder.Vendor") work?

UPDATE based on Craig's answer.

Rather than cast the result as an ObjectQuery<> (a cool little trick by itself), I just wrote the query in two stages

var links = from link in context.PO2Item.Include("PurchaseOrder.Vendor").AsNoTracking()
            where link.OrderLineItemId == lineItem.CostSourceLineItemId
            select link;

var po_2_item = links.FirstOrDefault();
return po_2_item == null ? null : po_2_item.PurchaseOrder;

The returned PO (if one exists) now has the Vendor set properly.

See this answer for a more elegant solution.

Upvotes: 3

Views: 482

Answers (2)

StriplingWarrior
StriplingWarrior

Reputation: 156524

I know this is already answered, but why not just do this?

// Get the purchase order (with Vendor) that has the given PO2Item
var po = context.PurchaseOrder.Include("Vendor").AsNoTracking().FirstOrDefault(
    o => o.PO2Item.Any(i => i.OrderLineItemId == lineItem.CostSourceLineItemId));

Upvotes: 1

Craig Stuntz
Craig Stuntz

Reputation: 126547

.Include() works on the shape of the returned query.

Your query returns a PurchaseOrder, not a PO2Item.

You need something more like (Guessing at the types here -- you may be using DbSet -- adjust accordingly):

var po = ((ObjectQuery<PurchaseOrder>)
         (from item in context.PO2Item
          where item.OrderLineItemId == lineItem.CostSourceLineItemId
          select item.PurchaseOrder))
         .Include("Vendor")
         .AsNoTracking()
         .FirstOrDefault();

Upvotes: 2

Related Questions