我一直在做很多关于Paging的研究,我被困在两种方法之间。使用这两种方法,我将使用PagedList.MVC来显示我的页面,但问题在于如何将数据传递给PagedList以及我的两种方法中的哪一种更有效。
我发现的最好的例子如下:
public static PagedList<Customer> GetPagedCustomers(int skip, int take)
{
using (var context = new AdventureWorksLTEntities())
{
var query = context.Customers.Include("SalesOrderHeaders")
.Where(c => c.SalesOrderHeaders.Any())
.OrderBy(c => c.CompanyName + c.LastName + c.FirstName);
var customerCount = query.Count();
var customers = query.Skip(skip).Take(take).ToList();
return new PagedList<Customer>
{
Entities = customers,
HasNext = (skip + 10 < customerCount),
HasPrevious = (skip > 0)
};
}
}
如果仔细查看该代码,实际上会发生2个查询,一个接一个。第一个是var customerCount = query.Count();
,第二个是var customers = query.Skip(skip).Take(take).ToList();
虽然我喜欢上面的查询方法非常轻,并且一次只能检索10条记录,但我不喜欢它会两次访问数据库。
我的第二种方法是更自定义,并且涉及直接在服务器上运行查询以及分页。现在这个查询正在与Dapper一起运行,但是如果这里的回复与我同意,我会按照我的方式工作。
SELECT *
FROM (
SELECT
*,1 as SplitOn,
(ROW_NUMBER() OVER(ORDER BY @SortColumn )) AS RowNum, COUNT(*) over() as TotalRows
FROM (
@CustomQuery
) AS FirstQuery
) AS TEMP
WHERE RowNum BETWEEN 1 + ((@Page - 1) * @PageSize) AND @Page * @PageSize
要用dapper解析它,代码看起来像这样
var simpleQuery = "Select * FROM Customers";
var finalQuery = string.Format(pageQuery, simpleQuery)
var obj = myWrapper();
using (var oConn = CreateConnection(ConnectionString))
{
TotalPages totalRows = null;
var list = oConn.Query<T, TotalPages, T>(finalQuery, (e, t) =>
{
totalRows = t;
if (mapAction != null) mapAction(e);
return e;
}, param, splitOn: "SplitOn");
}
obj.RowsFound = (IEnumerable<dynamic>)list;
obj.TotalRows = totalRows == null ? 0 : totalRows.TotalRows;
以上几项内容正在传递,例如类型<T>
,object param
,Action<T> mapAction
,这些事情对我的问题并不重要,因为问题是:< / p>
在第一个例子中,我要查询两次。在第二个例子中,我查询了一次,但我基本上做了1个查询和2个子查询。对于具有服务器百万条记录的表而言,这种方法更有效,并且由于它有大量流量而经常受到攻击。我的目标是理解在一个连接中在服务器上查询基本上3次更好。或者通过2个与数据库的单独连接进行2次查询。
编辑:
我更多地考虑了这一点,第一个例子实际上也是2个子查询。由于在调用ToList()方法之前查询的性质没有执行,它只会附加查询并构建它。
老实说,我真的相信第二种方法会更好,但我希望得到一些保证。