Miguel Moura
Miguel Moura

Reputation: 39374

Entity Framework 5. Multiple Include. Is this possible?

I am trying to create a multiple include method in my repository to use as follows:

repository.Include<Post>(x => x.Images, x => x.Tags).First(x => x.Id == 1)

I tried something as:

public IQueryable<T> Include<T>(params Expression<Func<T, Object>>[] paths) where T : class {
  return paths.Aggregate(_context.Set<T>(), (x, path) => x.Include(path));
} // Include

But I get the error:

Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Data.Entity.DbSet'.

Note that the original include is the following:

public static IQueryable Include( this IQueryable source, Expression> path ) where T : class;

Can I make this work without turning my repository method into static?

Thank You,

Miguel

Upvotes: 6

Views: 9672

Answers (3)

Alex Petuschak
Alex Petuschak

Reputation: 1048

I guess the shortest way is as follows:

public static class LinqExtensions
{
    /// <summary>
    /// Acts similar of .Include() LINQ method, but allows to include several object properties at once.
    /// </summary>
    public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params Expression<Func<T, object>>[] paths)
        where T : class
    {
        foreach (var path in paths)
            query = query.Include(path);

        return query;
    }
}

Upvotes: 0

Brikesh Kumar
Brikesh Kumar

Reputation: 149

public ICollection<SomeClass> Filter(string name, int skip, int take,out int total, params Expression<Func<SomeClass, object>>[] includeProperties) {
      IQueryable<SomeClass> query = Session.All<SomeClass>().AsNoTracking();
      //query = includeProperties.Aggregate(query, (current, property) => current.Include(property));
      foreach (var property in includeProperties){
          query = query.Include(property);
      }

      if (!string.IsNullOrWhiteSpace(name)){
          query = query.Where(x => x.Name.Contains(name));
          var page = query.OrderBy(x => x.Name)
              .Skip(skip)
              .Take(take)
              .GroupBy(p => new{Total = query.Count()})
              .FirstOrDefault();
         total = (page != null) ? page.Key.Total : 0;
         if (page == null) {
            return new List<SomeClass>();
         }
         return  page.ToList();
      } else {
          var page = query.OrderBy(x => x.Name)
              .Skip(skip)
              .Take(take)
              .GroupBy(p => new { Total = query.Count() })
              .FirstOrDefault();
          total = (page != null) ? page.Key.Total : 0;
          if (page == null) {
             return new List<SomeClass>();
          }
          return page.ToList();
      }
  }

Upvotes: 0

user743382
user743382

Reputation:

If you really want to create your own .Include non-extension method that allows for multiple paths in one call, internally translating to the already provided .Include method, you can do something like

public IQueryable<T> Include<T>(params Expression<Func<T, object>>[] paths)
    where T : class
{
    IQueryable<T> query = _context.Set<T>();
    foreach (var path in paths)
        query = query.Include(path);
    return query;
}

This is pretty close to what you have already, but avoids the pitfall with Enumerable.Aggregate that you encountered: you'd have the same problem if you replace IQueryable<T> query with var query in my version.

Note that using many .Include may harm performance. If it does in your situation, you can rewrite it to use multiple queries, which you can run one after the other in a transaction.

Personally, as you can call the already provided .Include extension method (using System.Data.Entity;) on any IQueryable, I'd just write it as:

repository.Posts.Include(x => x.Images).Include(x => x.Tags).First(x => x.Id == 1)

Upvotes: 9

Related Questions