实体框架 5.0. 多个 Include。这是可能的吗?

6

我正在尝试创建一个多重包含方法以在我的存储库中使用,用法如下:

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

我尝试了以下内容:

我试过如下:

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

但我遇到了以下错误:

无法隐式转换类型'System.Linq.IQueryable'为'System.Data.Entity.DbSet'。

请注意,原始的包含语句如下:

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

我能否在不将存储库方法转换为静态方法的情况下使其正常工作?

谢谢您,

Miguel


你只需要执行 _context.Set<T>().AsQueryable() - Gert Arnold
3个回答

9
如果你真的想要创建自己的.Include非扩展方法,可以在内部实现将多个路径翻译成已提供的.Include方法。你可以这样做:
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;
}

这和你已经有的很接近了,但避免了你遇到的Enumerable.Aggregate的陷阱:如果在我的版本中将IQueryable<T> query替换为var query,则会遇到相同的问题。
请注意,使用多个.Include可能会影响性能。如果在你的情况下确实如此,你可以将其重写为使用多个查询,并且你可以在事务中一个接一个地运行这些查询。
就我个人而言,由于你可以在任何IQueryable上调用已提供的.Include扩展方法(using System.Data.Entity;),所以我只会将其编写为:
repository.Posts.Include(x => x.Images).Include(x => x.Tags).First(x => x.Id == 1)

为什么你说使用多个Include会影响性能?我已经关闭了Lazy Loading,所以有时候需要使用Include。当然,我只会包含我需要的实体。如果我不需要图片,我可以包含标签而不是图片。你的话中有什么我没有理解到的吗? - Miguel Moura
1
@Shapper a.Include(b).Include(c).Include(d).Include(e) 被翻译成了 SQL 语句 select * from a left join b on b... = a... left join c on c... = a... left join d... = a... left join e... = a... 假设 a 有一条记录,bcde 每个都有 100 条。因此,您想要将 401 条记录加载到内存中。然而,EF 必须在 SQL 结果集中过滤 1 亿条记录才能获取这 401 个实体。 - user743382
我明白了...我只是举例说明我也可以查询context.Entry(post).Collection(x => x.Tags).Query().Select(x => x.Name)...谢谢你的帮助。 - Miguel Moura
嗨,我正在使用类似的模式,并且已经关闭了懒加载和代理。当我检查EF生成的SQL时,所有子项都包含在一个查询中。但是子对象仍然没有被填充。你能帮帮我吗? - Brikesh Kumar
@BrikeshKumar 请不要把问题发布为答案。您可以删除此处的内容,并将其作为新问题发布。 - user743382
显示剩余6条评论

0

我想最短的方法如下:

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;
    }
}

0
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();
      }
  }

好的,之前我在一个查询中获取了计数和结果。但是当懒加载关闭时,这种方法不起作用。因为我正在进行投影,所以包含部分不会被执行。删除 group by 后它就可以工作了。 - Brikesh Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接