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.
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?