C# 使用 LINQ 对对象进行分页
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2380413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Paging with LINQ for objects
提问by user256890
How would you implement paging in a LINQ query? Actually for the time being, I would be satisfied if the sql TOP function could be imitated. However, I am sure that the need for full paging support comes up sooner later anyway.
您将如何在 LINQ 查询中实现分页?其实暂时如果能模仿sql TOP功能我就满足了。但是,我确信对完整分页支持的需求无论如何迟早会出现。
var queryResult = from o in objects
where ...
select new
{
A = o.a,
B = o.b
}
????????? TOP 10????????
采纳答案by David Pfeffer
You're looking for the Skip
and Take
extension methods. Skip
moves past the first N elements in the result, returning the remainder; Take
returns the first N elements in the result, dropping any remaining elements.
您正在寻找Skip
和Take
扩展方法。Skip
移过结果中的前 N 个元素,返回余数;Take
返回结果中的前 N 个元素,删除所有剩余元素。
See MSDN for more information on how to use these methods: http://msdn.microsoft.com/en-us/library/bb386988.aspx
有关如何使用这些方法的更多信息,请参阅 MSDN:http: //msdn.microsoft.com/en-us/library/bb386988.aspx
Assuming you are already taking into account that the pageNumber should start at 0 (decrease per 1 as suggested in the comments) You could do it like this:
假设您已经考虑到 pageNumber 应该从 0 开始(按照评论中的建议每 1 减少)您可以这样做:
int numberOfObjectsPerPage = 10;
var queryResultPage = queryResult
.Skip(numberOfObjectsPerPage * pageNumber)
.Take(numberOfObjectsPerPage);
Otherwise as suggested by @Alvin
否则按照@Alvin的建议
int numberOfObjectsPerPage = 10;
var queryResultPage = queryResult
.Skip(numberOfObjectsPerPage * (pageNumber - 1))
.Take(numberOfObjectsPerPage);
回答by Hyman Marchetti
EDIT - Removed Skip(0) as it's not necessary
编辑 - 删除了 Skip(0) 因为它不是必需的
var queryResult = (from o in objects where ...
select new
{
A = o.a,
B = o.b
}
).Take(10);
回答by Noel
( for o in objects
where ...
select new
{
A=o.a,
B=o.b
})
.Skip((page-1)*pageSize)
.Take(pageSize)
回答by Tomas Petricek
Using Skip
and Take
is definitely the way to go. If I were implementing this, I would probably write my own extension method to handle paging (to make the code more readable). The implementation can of course use Skip
and Take
:
使用Skip
和Take
绝对是要走的路。如果我要实现这个,我可能会编写自己的扩展方法来处理分页(使代码更具可读性)。实现当然可以使用Skip
和Take
:
static class PagingUtils {
public static IEnumerable<T> Page<T>(this IEnumerable<T> en, int pageSize, int page) {
return en.Skip(page * pageSize).Take(pageSize);
}
public static IQueryable<T> Page<T>(this IQueryable<T> en, int pageSize, int page) {
return en.Skip(page * pageSize).Take(pageSize);
}
}
The class defines two extension methods - one for IEnumerable
and one for IQueryable
, which means that you can use it with both LINQ to Objects and LINQ to SQL (when writing database query, the compiler will pick the IQueryable
version).
该类定义了两种扩展方法 - 一种 forIEnumerable
和一种 for IQueryable
,这意味着您可以将它与 LINQ to Objects 和 LINQ to SQL 一起使用(编写数据库查询时,编译器将选择IQueryable
版本)。
Depending on your paging requirements, you could also add some additional behavior (for example to handle negative pageSize
or page
value). Here is an example how you would use this extension method in your query:
根据您的分页要求,您还可以添加一些额外的行为(例如处理负数pageSize
或page
值)。以下是如何在查询中使用此扩展方法的示例:
var q = (from p in products
where p.Show == true
select new { p.Name }).Page(10, pageIndex);
回答by Bitfiddler
Don't know if this will help anyone, but I found it useful for my purposes:
不知道这是否会帮助任何人,但我发现它对我的目的有用:
private static IEnumerable<T> PagedIterator<T>(IEnumerable<T> objectList, int PageSize)
{
var page = 0;
var recordCount = objectList.Count();
var pageCount = (int)((recordCount + PageSize)/PageSize);
if (recordCount < 1)
{
yield break;
}
while (page < pageCount)
{
var pageData = objectList.Skip(PageSize*page).Take(PageSize).ToList();
foreach (var rd in pageData)
{
yield return rd;
}
page++;
}
}
To use this you would have some linq query, and pass the result along with the page size into a foreach loop:
要使用它,您需要一些 linq 查询,并将结果与页面大小一起传递到 foreach 循环中:
var results = from a in dbContext.Authors
where a.PublishDate > someDate
orderby a.Publisher
select a;
foreach(var author in PagedIterator(results, 100))
{
// Do Stuff
}
So this will iterate over each author fetching 100 authors at a time.
因此,这将迭代每个作者,一次获取 100 个作者。
回答by Lukazoid
Here is my performant approach to paging when using LINQ to objects:
这是我在使用 LINQ to objects 时进行分页的高性能方法:
public static IEnumerable<IEnumerable<T>> Page<T>(this IEnumerable<T> source, int pageSize)
{
Contract.Requires(source != null);
Contract.Requires(pageSize > 0);
Contract.Ensures(Contract.Result<IEnumerable<IEnumerable<T>>>() != null);
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
var currentPage = new List<T>(pageSize)
{
enumerator.Current
};
while (currentPage.Count < pageSize && enumerator.MoveNext())
{
currentPage.Add(enumerator.Current);
}
yield return new ReadOnlyCollection<T>(currentPage);
}
}
}
This can then be used like so:
然后可以像这样使用:
var items = Enumerable.Range(0, 12);
foreach(var page in items.Page(3))
{
// Do something with each page
foreach(var item in page)
{
// Do something with the item in the current page
}
}
None of this rubbish Skip
and Take
which will be highly inefficient if you are interested in multiple pages.
这些都不是垃圾Skip
,Take
如果您对多个页面感兴趣,这将是非常低效的。
回答by Randy
I use this extension method:
我使用这种扩展方法:
public static IQueryable<T> Page<T, TResult>(this IQueryable<T> obj, int page, int pageSize, System.Linq.Expressions.Expression<Func<T, TResult>> keySelector, bool asc, out int rowsCount)
{
rowsCount = obj.Count();
int innerRows = rowsCount - (page * pageSize);
if (innerRows < 0)
{
innerRows = 0;
}
if (asc)
return obj.OrderByDescending(keySelector).Take(innerRows).OrderBy(keySelector).Take(pageSize).AsQueryable();
else
return obj.OrderBy(keySelector).Take(innerRows).OrderByDescending(keySelector).Take(pageSize).AsQueryable();
}
public IEnumerable<Data> GetAll(int RowIndex, int PageSize, string SortExpression)
{
int totalRows;
int pageIndex = RowIndex / PageSize;
List<Data> data= new List<Data>();
IEnumerable<Data> dataPage;
bool asc = !SortExpression.Contains("DESC");
switch (SortExpression.Split(' ')[0])
{
case "ColumnName":
dataPage = DataContext.Data.Page(pageIndex, PageSize, p => p.ColumnName, asc, out totalRows);
break;
default:
dataPage = DataContext.vwClientDetails1s.Page(pageIndex, PageSize, p => p.IdColumn, asc, out totalRows);
break;
}
foreach (var d in dataPage)
{
clients.Add(d);
}
return data;
}
public int CountAll()
{
return DataContext.Data.Count();
}
回答by Todd A. Stedel
var pages = items.Select((item, index) => new { item, Page = index / batchSize }).GroupBy(g => g.Page);
Batchsize will obviously be an integer. This takes advantage of the fact that integers simply drop decimal places.
Batchsize 显然是一个整数。这利用了整数简单地删除小数位的事实。
I'm half joking with this response, but it will do what you want it to, and because it's deferred, you won't incur a large performance penalty if you do
我对这个响应半开玩笑,但它会做你想做的事,而且因为它被推迟,如果你这样做,你不会招致很大的性能损失
pages.First(p => p.Key == thePage)
This solution is not for LinqToEntities, I don't even know if it could turn this into a good query.
此解决方案不适用于 LinqToEntities,我什至不知道它是否可以将其变成一个好的查询。
回答by Alen.Toma
public LightDataTable PagerSelection(int pageNumber, int setsPerPage, Func<LightDataRow, bool> prection = null)
{
this.setsPerPage = setsPerPage;
this.pageNumber = pageNumber > 0 ? pageNumber - 1 : pageNumber;
if (!ValidatePagerByPageNumber(pageNumber))
return this;
var rowList = rows.Cast<LightDataRow>();
if (prection != null)
rowList = rows.Where(prection).ToList();
if (!rowList.Any())
return new LightDataTable() { TablePrimaryKey = this.tablePrimaryKey };
//if (rowList.Count() < (pageNumber * setsPerPage))
// return new LightDataTable(new LightDataRowCollection(rowList)) { TablePrimaryKey = this.tablePrimaryKey };
return new LightDataTable(new LightDataRowCollection(rowList.Skip(this.pageNumber * setsPerPage).Take(setsPerPage).ToList())) { TablePrimaryKey = this.tablePrimaryKey };
}
this is what i did. Normaly you start at 1 but in IList you start with 0. so if you have 152 rows that mean you have 8 paging but in IList you only have 7. hop this can make thing clear for you
这就是我所做的。通常你从 1 开始,但在 IList 中你从 0 开始。所以如果你有 152 行,这意味着你有 8 个分页,但在 IList 中你只有 7。跳这可以让你清楚
回答by Debendra Dash
var results = (medicineInfo.OrderBy(x=>x.id)
.Skip((pages -1) * 2)
.Take(2));