Search code examples
c#entity-frameworkentity-framework-4

Entity Framework 4 related entity not loading


I use queries in EF4 to pull back records and process information through various other means (not EF) based on the data within, so I frequently have detached EF objects in lists.

In this case, I have a query in EntityFramework 4.0 that is not loading a related entity, even though I am using the .Include("...") method.

using (MyDBEntities ctx = new MyDBEntities())
{
    ctx.ContextOptions.LazyLoadingEnabled = false;

    // Get the first X records that need to be processed
    var q = (from t in ctx.DBTables
                .Include("Customer")
             let c = t.Customer
             where t.statusID == (int)Enums.Status.PostProcessing
             && c.isActive == true
             select t
            ).Take(batchSize).ToList();

    foreach (DBTable t in q)
    {
        // this results in c == null
        Customer c = t.Customer;

        // However t.CustomerID has a value, thus I know 
        // that t links to a real Customer record
        Console.WriteLine(t.CustomerID);
    }
}

Can anyone help me understand why Customer is not loading, even though I am explicitly stating to include it?


Solution

  • I found the root of the issue! The demon lies in the "let" command. Whenever I have a let, or a second "from" clause (like a join), then the ".Includes" get ignored!!!

    // -- THIS FAILS TO RETRIEVE CUSTOMER
    // Get the first X records that need to be processed
    var q = (from t in ctx.DBTables
                .Include("Customer")
             // Using a "let" like this or 
             let c = t.Customer
             // a "from" like this immediately causes my include to be ignored.
             from ca in c.CustomerAddresses
             where t.statusID == (int)Enums.Status.PostProcessing
             && c.isActive == true
             && ca.ValidAddress == true
             select t
            ).Take(batchSize).ToList();
    

    However, I can go get the ID's that I need to fetch in one call, then have a second "go get my includes" call, and everything works just fine.

    // Get the first X record IDs that need to be processed
    var q = (from t in ctx.DBTables
             let c = t.Customer
             from ca in c.CustomerAddresses
             where t.statusID == (int)Enums.Status.PostProcessing
             && c.isActive == true
             && ca.ValidAddress == true
             select t.TableID
            ).Take(batchSize).ToList();
    
    // Now... go "deep-load" the records I need by ID
    var ret = (from t in ctx.DBTables
                .Include("Customer")
               where q.Contains(t.TableID)
               select t);