Search code examples
entity-framework-4

Entity Framework - Programmatically add Includes to ObjectQuery


I have a Entity Framework model where I have a user which has the following relationships:

User 1-* Test

Each Test has the following relationships:

Test 1-1 Course
Test 1-* TestEvent

I have a service that returns a user and at different points in my application I want to eagerly fetch various relationships. I am fetching all the relationships at present:

var result = (from appUser in context.AppUsers.Include("Tests.Course")
    .Include("Tests.TestEvents")
    where appUser.Login.ToLower() == loginName.ToLower() &&
    appUser.IsDeleted == false
    select appUser).FirstOrDefault();

I do not want to always return the Course linked to a Test or the TestEvents. How can I build an ObjectQuery and dynamically add the Include statements as required rather than having a series of if else statements.


Solution

  • Well, since Include returns an IQueryable<T> (LINQ chainable), i would use a simple extension method:

    public static IQueryable<T> WithIncludes<T>(this IQueryable<T> source, string[] associations)
    {
       var query = (ObjectQuery<T>)source;
    
       foreach (var assoc in associations)
       {
          query = query.Include(assoc);
       }
    }
    

    Then your query looks like this:

    var inclusions = new[] { "Tests.Course", "Tests.TestEvents" };
    var result = ctx.AppUsers
                    .WithIncludes(inclusions)
                    .Where(x => x.Login.ToLower() == loginName.ToLower())
                    .Where(x => !x.IsDeleted)
                    .FirstOrDefault();
    

    To get some strong-typing into the otherwise magic-string nature of include, i have specialized enums for all associations, so i pass an [] of those through and convert the enum to the string include.

    The thing is, your methods should define what inclusions are required. So first thing you do in the method is declare what associations are required, then pass that to your extension method.

    Is that what your after?