如何使用Entity Framework返回部分结果和查询总数?

时间:2015-04-10 19:33:44

标签: asp.net-mvc linq entity-framework

我在Entity Framework中有这个查询:

_context.Onlines
                .Where(x => x.Date >= startDate.Date && x.Date <= endDate.Date && x.User.Id == userId)
                .OrderByDescending(x => x.Date)
                .Skip((int)size * (page - 1))
                .Take((int)size)
                .ToList();

你怎么看,我正在用“Skip”和“Take”进行分页搜索,我需要享受这个查询来计算这个查询的总结果(不仅是分页的部分计数),还有将结果,同一请求中的所有内容返回给数据库。

我需要这个来计算视图中的分页。

3 个答案:

答案 0 :(得分:3)

你可以这样做:

var query = _context.Onlines
    .Where(x => x.Date >= startDate.Date && x.Date <= endDate.Date && x.User.Id == userId);

// getting just count
int totalCount = query.Count();

// and then getting items itself
var items = query
    .OrderByDescending(x => x.Date)
    .Skip((int)size * (page - 1))
    .Take((int)size)
    .ToList();

它将根据原始条件生成两个SQL查询。一个用于计数,第二个用于项目。

答案 1 :(得分:1)

您可以使用Entity Framework Extended在一个事务中执行此操作。这是一个你可以找到的nuget包。我将引导您完成我们为服务器端分页所做的决定。

我们需要返回的列表和总记录数。 KeyValuePair<int, List<WhateverReturnModel>>应该很好用。

让我们来看看我们现在应该采取的措施。

  1. 创建一个分页请求模型,其默认PageNumber为x,PageSize为z。

    public class PagedRequest
    {
        private int? _pageNumber;
        private int? _pageSize;
        private int? _pageSkip;
    
        public int PageNumber
        {
            get { return this._pageNumber ?? 1; }
            set { this._pageNumber = value; }
        }
    
        public int PageSize
        {
            get { return this._pageSize ?? 15; }
            set { this._pageSize = value; }
        }
    }
    
  2. 设置返回方法以处理KeyValuePair结果

    protected KeyValuePair<int, List<T>> PagedResult<T>(int count, List<T> list)
    {
        return new KeyValuePair<int, List<T>>(count, list);
    }
    
  3. 将这些添加到需要分页的端点

    public KeyValuePair<int, List<WhateverModel>> DoSomething([FromUri] PagedRequest paged) 
    {
        var records = yourContext.YourTable.Where(t => true);
    
        var count = records.FutureCount() // this will not execute right away.. only when it is finally called
    
        var data = yourContext.YourTable
                              .Where(t => t.Something)
                              .OrderBy(i => i.Anything)
                              .Skip(this.PageSkip(paged.PageNumber, paged.PageSize))
                              .Take(paged.PageSize)
                              .Future() // again this will not execute right away
    
        return this.PagedResult(count, data.ToList()); // now both queries will execute in one call
    }
    
  4. 使用分页方法的API方法。

    public HttpResponseMessage DoAnotherThing() 
    {
        var test = new WhateverClass.DoSomething();
        return this.Paged(test);
    }
    
  5. 然后,您可以编写方法Paged(),它将返回KeyValuePair值作为响应内容,您可以为总计数添加标题。像这样......

    protected HttpResponseMessage OkPaged<T>(KeyValuePair<int, List<T>> content)
      var response = new HttpResponseMessage(HttpStatusCode.OK)
      {
          Content = new ObjectContent<Object>(content.Value, this.GetConfiguration().Formatters.JsonFormatter)
      };
    
      response.Headers.Add("x-paging-total", content.Key.ToString());
    
      return response; 
    }
    

答案 2 :(得分:1)

在单个查询中执行这两个操作不会产生任何性能优势。但是,可以使用nuget包EntityFrameworkPaginate以优雅的方式捕获分页数据。它的工作方式是你设置动态过滤和排序,你将得到一个Page对象作为结果,它将产生结果和元数据。 (CurrentPage,PageCount,PageSize,RecordCount和Results)。

首先,您需要设置过滤器。在你的情况下,你有一个条件。在基于不同条件的多个where子句的情况下,您可以将这些过滤器添加到过滤器对象。

 var filters = new Filters<Onlines>(); 
 filters.Add(true, x => x.Date >= startDate.Date 
                  && x.Date <= endDate.Date && x.User.Id == userId);

接下来,您需要按以下方式设置订单。在你的情况下,只有一个,但Sorts类也可以处理动态排序。

 var sorts = new Sorts<Onlines>();
 sorts.Add(true, x => x.Date, true);

现在要最终获取您的分页数据,您需要在dbset上调用扩展方法paginate。

Page<Onlines> paginatedData = context.Employees.Paginate(page, size, sorts, filters);

Voila,您将获得包含所有必需元数据的分页数据。这提供了一种干净的方法,在您进行动态过滤和排序时非常有用。您可以查看详细文章here