目录
背景
IEnumerable批量/分页帮助程序类
批量详细模型
实用程序/帮助程序类
使用List
使用实体框架
SQL Server的Db连接字符串设置
IQueryable,IDbSet
SQL或DbRawSqlQuery
- ListBatchAndPage_vs2017.zip - 12 KB
上周,我使用Entity Framework处理了大型数据对象列表。由于数据量很大,我不得不将它们分成多个小批量,并根据需要处理每个项。今天我将共享一个实用程序/帮助程序类来有效地批量/页面化源IEnumerable对象。
IEnumerable批量/分页帮助程序类 批量详细模型该模型将提供所有必要的批处理/分页详细信息。即我们可以使用此模型将分页数据绑定到前端。
public class BatchListDetail
{
public int PageNo { get; set; }
public int PageSize { get; set; }
public int TotalItem { get; set; }
public int TotalPage
{
get
{
var value = PageSize > 0
? (int)Math.Ceiling(TotalItem / (double)PageSize)
: 0;
return value;
}
}
public bool HasPreviousPage
{
get
{
var value = PageNo > 1;
return value;
}
}
public bool HasNextPage
{
get
{
var value = PageNo < TotalPage;
return value;
}
}
}
实用程序/帮助程序类
在这个帮助类中,我们将获得三种不同的扩展方法
- 获取给定页码的分页/批量数据。
- 从给定的页码开始,获取多页面列表中的所有数据。
- 获得top(SQL top)数据。请在我们要处理的大型列表中的每个项的场景中使用此项,并且在处理之后,该项将不再可用于下一批次查询。
using System;
using System.Collections.Generic;
using System.Linq;
public static class EnumerableHelper
{
///
/// Total list detail with current page data
///
public static List Batch(this IEnumerable source, int pageNo, int pageSize, out BatchListDetail details) where T : class
{
List list = new List();
details = new BatchListDetail();
if (pageNo < 1)
{
throw new ArgumentOutOfRangeException("pageNo minimum value should be 1.");
}
if (pageSize < 1)
{
throw new ArgumentOutOfRangeException("pageSize pageSize value should be 1.");
}
int totalItem = source == null ? 0 : source.Count();
if (totalItem == 0)
{
return list;
}
/*batch list details*/
details.PageNo = pageNo;
details.PageSize = pageSize;
details.TotalItem = totalItem;
/*resut*/
list = pageNo == 1
? source.Take(pageSize).ToList()
: source.Skip((pageNo - 1) * pageSize).Take(pageSize).ToList();
return list;
}
///
/// Total list to multiple split list
///
public static IEnumerable Batchs(this IEnumerable source, int startingFromPage, int size) where T : class
{
BatchListDetail details;
do
{
yield return source.Batch(startingFromPage, size, out details);
++startingFromPage;
}
while (details.HasNextPage);
}
///
/// Use in a scenario when we are going to process each item of a large list, batch wise.
/// Need to process the item in a way so that, after processing this will not be available on next batch query anymore.
///
public static bool Batch(this IEnumerable source, int size, out List result) where T : class
{
result = source.Take(size).ToList();
return result.Any();
}
}
使用List
这里我们用List / IList对象测试帮助程序类
/*list*/
List sourceList = Data.Peoples(TotalItem);
/*queryable*/
//IQueryable sourceList = Data.Peoples(TotalItem).AsQueryable();
/*page wise data*/
BatchListDetail details;
List batch = sourceList.Batch(1, 3, out details).ToList();
/*full list to multiple paged list*/
List batchs = sourceList.Batchs(1, 3).ToList();
/*get batch data, process and do same until all processed*/
var query = sourceList.Where(x => !x.IsActive);
List resultList;
while (query.Batch(3, out resultList))
{
foreach (var item in resultList)
{
item.IsActive = true;
}
}
使用实体框架
SQL Server的Db连接字符串设置
- 在app.config文件中更改连接字符串
- 在包管理器控制台中键入Update-Database
现在我们很好地连接到我们的本地SQL Server。让我们在我们的数据库中填充一些样本数据用于测试目的
Db db = new Db();
db.People.RemoveRange(db.People); /*remove old data*/
db.SaveChanges();
db.People.AddRange(Data.Peoples(TotalItem)); /*add new data*/
db.SaveChanges();
IQueryable,IDbSet
这里我们使用Entity Framework 和IQueryable,IDbSet 对象测试实用程序类。
/*table*/
BatchListDetail details;
/*page wise data*/
List batch = db.People.Batch(1, 3, out details).ToList();
/*full list to multiple paged list*/
List batchs = db.People.Batchs(1, 3).ToList();
/*get batch data, process and do same until all processed*/
var query = db.People.Where(x => !x.IsActive);
List resultList;
while (query.Batch(3, out resultList))
{
foreach (var item in resultList)
{
item.IsActive = true;
}
db.SaveChanges(); /*save to db*/
}
/*all data*/
List list = db.People.ToList();
SQL或DbRawSqlQuery
现在让我们用DbRawSqlQuery(SQL查询结果对象) 尝试测试帮助程序类
/*sql query to model*/
BatchListDetail modelDetails;
/*page wise data*/
List modelBatch = db.Peoples().Batch(1, 3, out modelDetails).ToList();
/*full list to multiple paged list*/
List modelBatchs = db.Peoples().Batchs(1, 3).ToList();
/*get batch data, process and do same until all processed*/
var modeQuery = db.Peoples().Where(x => x.IsActive);
List modelResultList;
while (modeQuery.Batch(3, out modelResultList))
{
foreach (var item in modelResultList)
{
People people = db.People.Find(item.Id);
people.IsActive = false;
}
db.SaveChanges(); /*save to db*/
}
/*all data*/
List modelList = db.Peoples().ToList();
说明
- 在处理大型数据集时,yield return是您最好的朋友
- 其他可用的配料解决方案
- https://github.com/troygoode/PagedList
- https://github.com/morelinq/MoreLINQ
- https://stackoverflow.com/a/34665432/2948523
原文地址:https://www.codeproject.com/Tips/4114424/List-Batching-Paging-With-Entity-Framework-or-Any