与分页相结合的区别

时间:2015-10-14 11:59:10

标签: .net entity-framework linq tsql pagination

设置:MS sql 2012,EF 6.1.3,Web Api 2和.NET 4.52

我目前正在使用具有此布局的表:

Table layout

该表最终会变得非常大,所以当客户端获取这样的数据时我需要分页:

客户< ----> Web api 2< ---->实体框架< -----> MS SQL

所以..这是交易。我需要Email,Brand和Type_Id的每个独特组合的最新行(最高" createdAt") 将为每个电话设置品牌,以便我可以对其进行过滤。

我现在这样做的方式是这样的:

var result = _context.Permissions.Where(p => p.Brand == brandEnum)
            .Include(p => p.Type)
            .Include(p => p.UserType)
            .OrderByDescending(o => o.CreatedAt)
            .DistinctBy(p => new {p.Type, p.Email})
            .Skip(pageSize*(page - 1))
            .Take(pageSize);


 public static class LinqExtensions {

        public static IEnumerable<T> DistinctBy<T>(this IEnumerable<T> list, Func<T, object> propertySelector)
        {
            return list.GroupBy(propertySelector).Select(x => x.First());
        }

    }

好的,这就是问题所在。这是有效的,但是速度非常慢,因为它的实现方式是强制DB在每次调用时检索所有行,这最终会消除关于分页的整个想法。删除&#34; DistinctBy&#34;过滤器解决了速度问题,但现在也会返回较旧(不再有效)的数据。

所以我希望有人有一个有利于速度和功能的解决方案。

提前致谢。

2 个答案:

答案 0 :(得分:0)

虽然我不确定它是否有更好的性能,但只能在您身边检查,这里有一些建议:

var result = _context.Permissions.Where(p => p.Brand == brandEnum)
                     .GroupBy(p => new {p.Type, p.Email})
                     .Select(g => g.OrderByDescending(o => o.CreatedAt)
                                   .FirstOrDefault())
                     .OrderByDescending(o => o.CreatedAt)
                     .Skip(pageSize*(page - 1))
                     .Take(pageSize)
                     .Include(p => p.Type)
                     .Include(p => p.UserType);

答案 1 :(得分:0)

正如@KingKing建议的那样,您应该在扩展方法中按IEnumerable<T>更改IQueryable<T>类型:

  public static IQueryable<T> DistinctBy<T>(this IQueryable<T> query, Func<T, object> propertySelector)
  {
        return query.GroupBy(propertySelector).Select(x => x.FirstOrDefault());
  }

这就是我的查询方式:

var result = _context.Permissions.Where(p => p.Brand == brandEnum)
                                 .Include(p => p.Type)
                                 .Include(p => p.UserType)
                                 .GroupBy((p => new {p.Type, p.Email})
                                 .Select(x => x.OrderByDescending(o => o.CreatedAt).FirstOrDefault())
                                 .Skip(pageSize*(page - 1))
                                 .Take(pageSize);

如果您需要继续使用DistincBy方法,我建议您移动该方法内的OrderByDescending来调整群组:

  public static IQueryable<T> DistinctBy<T>(this IQueryable<T> query, Func<T, object> propertySelector, IOrderedQueryable<TEntity>> orderBy = null)
  {
        var q=query.GroupBy(propertySelector);
        if(orderBy!=null)
          q= orderBy(q);
        return q.Select(x => x.FirstOrDefault());
  }

您的查询将是这样的:

var result = _context.Permissions.Where(p => p.Brand == brandEnum)
                                 .Include(p => p.Type)
                                 .Include(p => p.UserType)
                                 .DistinctBy(p => new {p.Type, p.Email},q=>q.OrderByDescending(o => o.CreatedAt))
                                 .Skip(pageSize*(page - 1))
                                 .Take(pageSize);

在这种情况下,orderBy参数是可选的。