Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is EF eager loading include not working as expected?

I have this repository,

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly DbContext context;
    private readonly DbSet<TEntity> dbEntitySet;

    public Repository(DbContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        this.context = context;
        this.dbEntitySet = context.Set<TEntity>();
    }

    public IEnumerable<TEntity> GetAll()
    {
        return this.dbEntitySet;
    }

    public IEnumerable<TEntity> GetAll(string include)
    {
        return this.dbEntitySet.Include(include);
    }

    public IEnumerable<TEntity> GetAll(string[] includes)
    {
        foreach (var include in includes)
            this.dbEntitySet.Include(include);

        return this.dbEntitySet;
    }

    public void Create(TEntity model)
    {
        this.dbEntitySet.Add(model);
    }

    public void Update(TEntity model)
    {
        this.context.Entry<TEntity>(model).State = EntityState.Modified;
    }

    public void Remove(TEntity model)
    {
        this.context.Entry<TEntity>(model).State = EntityState.Deleted;
    }

    public void Dispose()
    {
        this.context.Dispose();
    }
}

and the issue I have is with this method:

public IEnumerable<TEntity> GetAll(string[] includes)
{
    foreach (var include in includes)
        this.dbEntitySet.Include(include);

    return this.dbEntitySet;
}

When I run it and put a breakpoint before the return, it is as if the foreach is being ignored.

the method above it works fine:

public IEnumerable<TEntity> GetAll(string include)
{
    return this.dbEntitySet.Include(include);
}

To call it, I basically do this:

var a = this.Repository.GetAll(new string[] { "ForbiddenUsers", "ForbiddenGroups" }).ToList();

which pulls back the results but not does include the includes :D If I modify the call to:

var a = this.Repository.GetAll("ForbiddenUsers").ToList();

It works fine.

Can someone provide me with a resolution?

like image 476
r3plica Avatar asked Jan 15 '14 16:01

r3plica


2 Answers

Change your method to look like this:

public IEnumerable<TEntity> GetAll(string[] includes)
{
    var query = this.dbEntitySet;

    foreach (var include in includes)
        query = query.Include(include);

    return query;
}

The Include method does not mutate the DbSet, it only returns you a new DbQuery with your include.

like image 129
luksan Avatar answered Sep 21 '22 10:09

luksan


This code is incorrect:

public IEnumerable<TEntity> GetAll(string[] includes)
{
    foreach (var include in includes)
       this.dbEntitySet.Include(include);

    return this.dbEntitySet;
}

The correct code is the following:

public IEnumerable<TEntity> GetAll(string[] includes)
{
     IQueryable<T> query = this.dbEntitySet;

     foreach (var include in includes)
         query = query.Include(include);

    return query;
}

In your place I will use Lambda Expressions like this:

public IEnumerable<TEntity> GetAll(Expression<Func<T, object>>[] includes)
{
     IQueryable<T> query = this.dbEntitySet;

     foreach (var include in includes)
         query = query.Include(include);

     return query;
}
like image 32
CodeNotFound Avatar answered Sep 22 '22 10:09

CodeNotFound