如何在LINQ查询中实现分页? 实际上,如果可以模仿sql TOP函数,我会感到满意。但是,我确信无论如何都需要尽快提供完整的寻呼支持。
var queryResult = from o in objects
where ...
select new
{
A = o.a,
B = o.b
}
????????? TOP 10????????
答案 0 :(得分:198)
您正在寻找Skip
和Take
扩展方法。 Skip
移过结果中的前N个元素,返回余数; Take
返回结果中的前N个元素,删除任何剩余的元素。
有关如何使用这些方法的详细信息,请参阅MSDN:http://msdn.microsoft.com/en-us/library/bb386988.aspx
例如:
int numberOfObjectsPerPage = 10;
var queryResultPage = queryResult
.Skip(numberOfObjectsPerPage * pageNumber)
.Take(numberOfObjectsPerPage);
答案 1 :(得分:49)
使用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);
}
}
该类定义了两个扩展方法 - 一个用于IEnumerable
,一个用于IQueryable
,这意味着您可以将它与LINQ to Objects和LINQ to SQL一起使用(在编写数据库查询时,编译器将选择IQueryable
版本。
根据您的分页要求,您还可以添加一些其他行为(例如,处理否定的pageSize
或page
值)。以下是如何在查询中使用此扩展方法的示例:
var q = (from p in products
where p.Show == true
select new { p.Name }).Page(10, pageIndex);
答案 2 :(得分:29)
这是我在使用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);
}
}
}
然后可以这样使用:
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
}
}
如果您对多个页面感兴趣,那么这些垃圾Skip
和Take
都不会非常低效。
答案 3 :(得分:8)
( for o in objects
where ...
select new
{
A=o.a,
B=o.b
})
.Skip((page-1)*pageSize)
.Take(pageSize)
答案 4 :(得分:5)
编辑 - 删除跳过(0),因为没有必要
var queryResult = (from o in objects where ...
select new
{
A = o.a,
B = o.b
}
).Take(10);
答案 5 :(得分:5)
不知道这是否会对任何人有所帮助,但我发现它对我的目的很有用:
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++;
}
}
要使用它,您将获得一些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
}
因此,这将迭代每个作者一次获取100位作者。
答案 6 :(得分:3)
var pages = items.Select((item, index) => new { item, Page = index / batchSize }).GroupBy(g => g.Page);
Batchsize显然是一个整数。这利用了整数只是丢弃小数位的事实。
我对这个回应是开玩笑的,但是它会做你想要的,并且因为它推迟了,如果你这样做,你不会招致很大的性能损失
pages.First(p => p.Key == thePage)
此解决方案不适用于LinqToEntities,我甚至不知道它是否可以将其变成一个好的查询。
答案 7 :(得分:2)
与Lukazoid's answer类似,我为IQueryable创建了一个扩展名。
public static IEnumerable<IEnumerable<T>> PageIterator<T>(this IQueryable<T> source, int pageSize)
{
Contract.Requires(source != null);
Contract.Requires(pageSize > 0);
Contract.Ensures(Contract.Result<IEnumerable<IQueryable<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);
}
}
}
如果不支持Skip或Take,这很有用。
答案 8 :(得分:1)
我使用这种扩展方法:
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();
}
答案 9 :(得分:1)
data = data.Where(x => x != 0).ToArray();
这就是我所做的。 Normaly从1开始,但在IList中,你从0开始。 所以如果你有152行意味着你有8个分页,但在IList中你只有7个。 跳这可以让你清楚
答案 10 :(得分:1)
var results = (medicineInfo.OrderBy(x=>x.id)
.Skip((pages -1) * 2)
.Take(2));
答案 11 :(得分:1)
有两个主要选项:
.NET&gt; = 4.0 Dynamic LINQ:
var people = people.AsQueryable().OrderBy("Make ASC, Year DESC").ToList();
您也可以通过NuGet获取它。
.NET&lt; 4.0 强> Extension Methods:
private static readonly Hashtable accessors = new Hashtable();
private static readonly Hashtable callSites = new Hashtable();
private static CallSite<Func<CallSite, object, object>> GetCallSiteLocked(string name) {
var callSite = (CallSite<Func<CallSite, object, object>>)callSites[name];
if(callSite == null)
{
callSites[name] = callSite = CallSite<Func<CallSite, object, object>>.Create(
Binder.GetMember(CSharpBinderFlags.None, name, typeof(AccessorCache),
new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
}
return callSite;
}
internal static Func<dynamic,object> GetAccessor(string name)
{
Func<dynamic, object> accessor = (Func<dynamic, object>)accessors[name];
if (accessor == null)
{
lock (accessors )
{
accessor = (Func<dynamic, object>)accessors[name];
if (accessor == null)
{
if(name.IndexOf('.') >= 0) {
string[] props = name.Split('.');
CallSite<Func<CallSite, object, object>>[] arr = Array.ConvertAll(props, GetCallSiteLocked);
accessor = target =>
{
object val = (object)target;
for (int i = 0; i < arr.Length; i++)
{
var cs = arr[i];
val = cs.Target(cs, val);
}
return val;
};
} else {
var callSite = GetCallSiteLocked(name);
accessor = target =>
{
return callSite.Target(callSite, (object)target);
};
}
accessors[name] = accessor;
}
}
}
return accessor;
}
public static IOrderedEnumerable<dynamic> OrderBy(this IEnumerable<dynamic> source, string property)
{
return Enumerable.OrderBy<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> OrderByDescending(this IEnumerable<dynamic> source, string property)
{
return Enumerable.OrderByDescending<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenBy(this IOrderedEnumerable<dynamic> source, string property)
{
return Enumerable.ThenBy<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenByDescending(this IOrderedEnumerable<dynamic> source, string property)
{
return Enumerable.ThenByDescending<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}