C# 对象的LINQ分页
如何在LINQ查询中实现分页? 实际上,就目前而言,如果可以模仿SQLtop函数,我会感到满意。但是,我确信,对完全分页支持的需求迟早会出现C# 对象的LINQ分页,c#,.net,linq,paging,C#,.net,Linq,Paging,如何在LINQ查询中实现分页? 实际上,就目前而言,如果可以模仿SQLtop函数,我会感到满意。但是,我确信,对完全分页支持的需求迟早会出现 var queryResult = from o in objects where ... select new { A = o.a, B =
var queryResult = from o in objects
where ...
select new
{
A = o.a,
B = o.b
}
????????? TOP 10????????
您正在寻找
Skip
和Take
扩展方法<代码>跳过移动经过结果中的前N个元素,返回剩余元素Take
返回结果中的前N个元素,删除所有剩余元素
有关如何使用这些方法的更多信息,请参见MSDN:
假设您已经考虑到页码应该从0开始(按照注释中的建议每1减少一次),您可以这样做:
int numberOfObjectsPerPage = 10;
var queryResultPage = queryResult
.Skip(numberOfObjectsPerPage * pageNumber)
.Take(numberOfObjectsPerPage);
否则,如果页码基于1(如@Alvin所建议)
编辑-已删除跳过(0),因为它不是必需的
var queryResult = (from o in objects where ...
select new
{
A = o.a,
B = o.b
}
).Take(10);
使用
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);
}
}
不知道这是否对任何人都有帮助,但我发现它对我的目的很有用:
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++;
}
}
因此,这将迭代每个作者,每次获取100个作者。以下是我使用LINQ对对象进行分页时的性能方法:
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);
}
}
}
如果您对多个页面感兴趣,那么这些垃圾跳过和获取将是非常低效的。我使用这种扩展方法:
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();
}
公共静态IQueryable页面(此IQueryable对象,int页面,int页面大小,System.Linq.Expressions.Expression键选择器,bool asc,out int rowsunt)
{
rowsCount=obj.Count();
int innerRows=ROWSCONT-(页面*页面大小);
如果(内部行<0)
{
innerRows=0;
}
如果(asc)
返回obj.OrderByDescending(keySelector).Take(innerRows).OrderBy(keySelector).Take(pageSize).AsQueryable();
其他的
返回obj.OrderBy(keySelector).Take(innerRows).OrderByDescending(keySelector).Take(pageSize).AsQueryable();
}
公共IEnumerable GetAll(int-RowIndex、int-PageSize、string-SortExpression)
{
整数行;
int pageIndex=行索引/页面大小;
列表数据=新列表();
IEnumerable数据页;
bool asc=!SortExpression.Contains(“DESC”);
开关(SortExpression.Split(“”)[0])
{
案例“ColumnName”:
dataPage=DataContext.Data.Page(pageIndex、PageSize、p=>p.ColumnName、asc、OutTotalRows);
打破
违约:
dataPage=DataContext.vwClientDetails1s.Page(pageIndex,PageSize,p=>p.IdColumn,asc,out totalRows);
打破
}
foreach(数据页中的变量d)
{
添加(d);
}
返回数据;
}
公共整数CountAll()
{
返回DataContext.Data.Count();
}
Batchsize显然是一个整数。这充分利用了整数只需删除小数位数这一事实
我半开玩笑的回答,但它会做你想做的,因为它是延迟的,如果你这样做,你不会招致很大的性能损失
pages.First(p => p.Key == thePage)
此解决方案不适用于LinqToEntities,我甚至不知道它是否能将此转化为一个好的查询。公共LightDataTable页面选择(int pageNumber,int setsPerPage,Func prection=null)
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.setsPerPage=setsPerPage;
this.pageNumber=pageNumber>0?pageNumber-1:pageNumber;
如果(!ValidatePagerByPageNumber(pageNumber))
归还这个;
var rowList=rows.Cast();
if(prection!=null)
rowList=行。其中(prection).ToList();
如果(!rowList.Any())
返回新的LightDataTable(){TablePrimaryKey=this.TablePrimaryKey};
//if(rowList.Count()<(页码*设置每页))
//返回新的LightDataTable(新的LightDataRowCollection(rowList)){TablePrimaryKey=this.TablePrimaryKey};
返回新的LightDataTable(新的LightDataRowCollection(rowList.Skip(this.pageNumber*SetPerPage).Take(SetPerPage.ToList()){TablePrimaryKey=this.TablePrimaryKey};
}
这就是我所做的。
通常从1开始,但在IList中从0开始。
所以,如果您有152行,这意味着您有8个分页,但在IList中,您只有7个分页。
这会让你明白的
var results=(medicineInfo.OrderBy(x=>x.id)
.跳过((第1页)*2页)
.采取(2)项措施代码>有两个主要选项:
.NET>=4.0
:
使用System.Linq.Dynamic添加;在顶端
用法:var people=people.AsQueryable().OrderBy(“Make ASC,Year DESC”).ToList()代码>
你也可以买它
.NET<4.0
:
私有静态只读哈希表访问器=新哈希表();
私有静态只读哈希表callSites=new Hashtable();
私有静态CallSite GetCallSiteLocked(字符串名称){
var callSite=(callSite)callSites[name];
if(callSite==null)
{
callSites[name]=callSite=callSite.Create(
Binder.GetMember(CSharpBinderFlags.None、name、typeof(AccessorCache),
新建CSharpArgumentInfo[]{CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,null)});
}
返回呼叫站点;
}
内部静态Func GetAccessor(字符串名称)
{
Func访问器=(Func)访问器[名称];
if(访问器==null)
{
锁(存取器)
{
访问器=(Func)访问器[名称];
if(访问器==null)
{
如果(name.IndexOf('.')>=0){
string[]props=name.Split('.');
CallSite[]arr=Array.ConvertAll(props,GetCallSiteLocked);
访问者=目标=>
{
对象val=(对象)目标;
对于(int i=0;ipublic 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
}
}
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();
}
var pages = items.Select((item, index) => new { item, Page = index / batchSize }).GroupBy(g => g.Page);
pages.First(p => p.Key == thePage)
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 };
}
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);
}
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);
}
}
}