How do i make .Include to work on an IEnumerable

6.5k views Asked by At

I'm having trouble running a query on my repository. I have to fetch a product by the id and display it in an edit view alongside the image of the product.

There is a method in my ProductRepository that implements Get() i.e fetch all the product and GetByID as the name implies. I implemented a generic repository pattern with a unit of work class like below

public class GenericRepository<TEntity> where TEntity : class
    {
        internal SchoolContext context;
        internal DbSet<TEntity> dbSet;

        public GenericRepository(SchoolContext context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual TEntity GetByID(object id)
        {
            return dbSet.Find(id);
        }

I think thats the only relevant code block. The problem arises when i try to run a query that i found in a tutorial to fetch the product alongside the image with the query below

Product product = db.Products.Include(s => s.Files).SingleOrDefault(s => s.ID == id);

I cant use db.Products because i'm using a unit of work class so i have to run the query with _unit.ProductRepository.GetByID().Include(s => s.Files).SingleOrDefault(s => s.ID == id);

However this does not seem to be possible and i'm stucked.

2

There are 2 answers

0
Marc Cals On

You can not use Include with a IEnumerable, It only works with IQueryable, when you invoke in your repository query.ToList(); you query is retrieved from database to memory in a IEnumerable and when your data is in memory Include doesn't work.

You can pass the objects that you want to include in your query as a parameter like you do with filter or order in your Get method.

You can override your ProductRepository method

    public override Product GetByID(object ID)
    {
        return db.Products.Include(p => p.Files).SingleOrDefault(p => p.ID == ID);
    }

or if you don't want always to return Files

    public override Product GetByID(object ID, List<string> includes)
    {

        var query = db.Products.AsQueryable();
        foreach (string include in includes)
        {
            query = query.Include(include);
       }

       return query.SingleOrDefault(p => p.ID == ID);
    }

And invoke like

 Product product = new ProductRepository().GetByID(IDProduct, new List<string>() { "Files" });
0
robrich On

Try this:

DbSet<TEntity> set = dbSet;

foreach (var includeProperty in includeProperties.Split
    (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
    set = set.Include(includeProperty);
}

IQueryable<TEntity> query = set;

if (filter != null)
{
    query = query.Where(filter);
}