使用Linq到Entities在一个操作中获取COUNT和SKIP TAKE



我在Linq to Entities支持的数据访问层中有一个数据调用,该层旨在进行分页调用。

在这样做的时候,我需要选择数据的一个子集,比如说50行,但也需要获得所有匹配的计数,以知道总共有多少匹配需要分页。

目前,我正在做以下工作:

var queryResult = DatabaseContext.Table
    .Where(x => !x.IsDeleted)
    .Where(p => (
            p.PropertyOne.ToLower().Contains(query) ||
            p.PropertyTwo.ToLower().Contains(query) 
            ));
int count = queryResult.Count();
var returnData = queryResult
    .OrderBy(i => i.ID)
    .Skip(start).Take((length))
    .Select(y => new ObjectDTO
    {
        PropertyOne = y.PropertyOne,
        PropertyTwo = y.PropertyTwo
    }
    .AsEnumerable();

这导致了两个代价高昂的数据库操作。由于某种原因,COUNT操作实际上比SELECT操作花费更长的时间。

有没有一种方法可以在同一操作中获得计数和子集?

对我来说,逻辑流程说我们做以下事情:

  • 查看表格
  • 在表中查找符合条件的项
  • 获取所有匹配项的计数
  • 返回匹配项的编号子集

这在一次手术中似乎是可能的,但我不知道怎么做。

尝试一次,速度较慢

尝试了D Stanley的建议,将整个结果集强制转换为List,并在分页中进行计数和内存,但大约慢了2倍(平均6.9秒vs平均3.9秒)

值得一提的是,数据集大约有25000条记录,在JOIN中搜索了十几个相关的表。

这可能是可能的,但由于您使用的标准,速度可能不会快很多。由于您在列值中搜索文本,因此不能使用索引,因此必须执行表扫描。可以执行单个查询以获取所有记录,并在linq中对对象执行CountSkip/Take

var queryResult = DatabaseContext.Table
    .Where(x => !x.IsDeleted)
    .OrderBy(i => i.ID)
    .Where(p => (
            p.PropertyOne.ToLower().Contains(query) ||
            p.PropertyTwo.ToLower().Contains(query) 
            ))
    .ToList();
int count = queryResult.Count();  // now this will be a linq-to-objects query
var returnData = queryResult
    .Skip(start).Take((length))
    .AsEnumerable();

但你得试试看它是否会更快。

这样的东西怎么样:

db.Products
   .Take(10)
   .Select(p => new 
                {
                    Total = db.Products.Count, 
                    Product = p
                })

如果这不好,那么在SQL中,您可以使用OVER()获得总结果和其中的一页结果,这可能会有所帮助。

最新更新