Home > Blockchain >  Entity Framework .Include() with condition not working
Entity Framework .Include() with condition not working

Time:12-30

SCENARIO

If I split the Entity Framework linq query to evaluate an IQuerable first and after try to include some properties, the value of "AccessGroupAccessPoints" and "AccessGroupAccessPoints.AccessPoint" will not be included in the end.

    public Task<List<AccessGroup>> GetAll(bool includeRelations)
    {
        var q = context.Set<AccessGroup>().AsNoTracking();

        if (includeRelations)
        {
            q.Include(a => a.AccessGroupAccessPoints)
                .ThenInclude(a => a.AccessPoint);
        }
        
        return q.ToListAsync();
    }

I also tried to remove ThenInclude(), use string as parameter of Include(), move AsNoTracking() to resolve after... Neither of these options worked.

    public Task<List<AccessGroup>> GetAll(bool includeRelations)
    {
        var q = context.Set<AccessGroup>();

        if (includeRelations)
        {
            q.Include("AccessGroupAccessPoints");
        }

        return q.AsNoTracking().ToListAsync();
    }

SOLUTION

But I found out a solution, if don't split the query until it evaluates the object List, Entity Framework includes the expected properties. I hope it help.

    public Task<List<AccessGroup>> GetAll(bool includeRelations)
    {
        if (includeRelations)
        {
            return context.Set<AccessGroup>()
                .Include(a => a.AccessGroupAccessPoints).ThenInclude(a => a.AccessPoint)
                .AsNoTracking()
                .ToListAsync();
        }
        else
        {
            return context.Set<AccessGroup>().AsNoTracking().ToListAsync();
        }
        
    }
    

QUESTIONS

Why it happens? Is this a Entity Framework bug?

CodePudding user response:

For a similar reason that this doesn't sort a list in place:

var x = new List<int> { 3, 2, 1 };

x.OrderBy(i => i);

Console.WriteLine(string.Join("|", x));    //prints 3,2,1

You need to capture and use the result of the OrderBy for it to have an effect:

var x = new List<int> { 3, 2, 1 };

var y = x.OrderBy(i => i);

Console.WriteLine(string.Join("|", y));    //prints 1,2,3

In your first code, you make q, then you call Include() on it, but don't use the return value from Include, and Include doesn't modify q so that it becomes something that does an include (just like calling OrderBy on a list doesn't jiggle its items so they are in order) so the knowledge of why you included is lost..

..yet, in your second code you use the return value from Include when you run the query (because of the chain)


Perhaps you need something like:

public Task<List<AccessGroup>> GetAll(bool includeRelations)
{
    var q = context.AccessGroups.AsQueryable();    //so we can assign the IIncludableQueryable generated by Include.ThenInclude back to q

    if (includeRelations)
    {
        q = q.Include(a => a.AccessGroupAccessPoints)
            .ThenInclude(a => a.AccessPoint);
    }
    
    return q.ToListAsync();
}
  • Related