我在SQL Server中有10万多行。我想以1000行为单位进行选择,例如1-1000,然后1001-2000,然后2001-3000 ...直到完成。
我使用此代码
var ff = ((from a in db.Customers select).Skip(i).Take(i+1000));
但是它不起作用。如果您还有其他解决方案,请给我建议。
答案 0 :(得分:2)
您没有选择任何东西,应该是
printArr(stuData:ObservableArray<StudentData>){
for(let i=0; i<stuData.length; i++)
console.log("PrintData:", stuData.getItem(i));
}
或流利地>
var ff = ((from a in db.Customers select a).Skip(i * 1000).Take(1000));
答案 1 :(得分:1)
有人建议查询您本地流程中的所有项目,然后使用“跳过/获取”将结果分为页面。
这样做的缺点是,如果在第三页之后发现您不再需要其他页面,则将浪费大量的处理能力:您什么也没拿到1000页。 LINQ的宏伟想法是尽可能延迟枚举:仅获取您实际需要的项目(也许更多)。
除此之外,每次请求下一页时,“跳过”都将从第一个元素开始,因此,如果您要求页面大小为100的页面1000,它将从第一个元素开始,然后跳过1000 * 100个元素在采取下一个步骤之前:多么浪费处理能力!
另一项建议是每次您要求页面时都要对完整的收藏进行排序。如果要获取第3页,为什么还要对第1000页中的元素进行排序?
显然您对客户的顺序不感兴趣,所以让我们按主键对其进行排序:宾果游戏:您的客户已经按主键进行了排序!
当请求页面时,我们会记住最后返回的元素的主键;当请求下一页时,我们将从第一个客户开始,其主键大于此最后一个。
我将其写为IQueryable<Customer>
的扩展功能,仅当您在枚举时要求下一页时,我才精确地获取一页。因此,如果您在获取第3页后停止枚举,则不会获取第4页及更高版本。
private static IEnumerable<ICollection<Customer>> ToPages(
this IQueryable<Customer> customers, int pageSize)
{
int lastFetchedCustomerId = 0; // no primary key fetched yet
// get the first page:
var page = customers.Where(customer => customer.Id > lastFetchedCustomerId)
.Take(pageSize)
.ToList();
// as long as there is a Customer in the page, return the page
while (page.Count != 0)
{ // there are customers
yield return page;
lastFetchedCustomerId = page[page.Count-1].Id;
page = customers.Where(customer => customer.Id > lastFetchedCustomerId)
.Take(pageSize)
.ToList();
}
}
用法:
using (var dbContext = new MyDbContext(...))
{
const int pageSize = 100
IEnumerable<ICollection<Customer>> customerPages = dbContext.Customers.ToPages(pageSize);
// note: nothing has been enumerated yet, no data has been fetched
foreach (var customerPage in customerPages)
{
// one page has been fetched, we can do something with the Customers in the page
foreach (Customer customer in customerPage)
{
ProcessCustomer(customer);
bool continueProcessingCustomers = ...;
if (!continueProcessingCustomers) return;
// so if you break in page 3, the other pages are not fetched!
}
}
}
请注意,您将始终每页获取客户。因此,如果您在处理完第三位客户后决定不需要该页面的其余客户,那么他们将一无所获。但这总是比吸引所有顾客更好。
最后,如果您知道所有DbSet
在属性ID中都具有主键,请考虑实现接口IId,以便ToCustomerPages可用于所有表:
interface IId
{
public int Id {get;}
}
class Customer : IId
{
public int Id {get; set; }
...
}
class Order : IId
{
public int Id {get; set; }
...
}
ToCustomerPages的通用版本:
private static IEnumerable<ICollection<TSource>> ToPages<TSource>(
this IQueryable<TSource> source, int pageSize)
where TSource: IId
{
...
}
现在您也可以在页面中获取订单了:
var orderPages = dbContext.Orders.ToPages(100);
答案 2 :(得分:0)
在Linq to Entities中,您必须对项目进行排序才能使用Skip
。比起Skip
,您可以跳过一些记录,而Take
中,您可以使用其他记录。
在下面的示例中,While
循环中,您每次都可以访问1000条记录(part
)。记录按Id
排序,必要时可以使用任何其他属性。 ToList()
是可选的,以实现您的结果。
根据Marnus的建议,您可以跳过获取所有物品的计数。
foreach (var page in db.Customers .OrderBy(x => x.Id).GetPages(1000))
{
// page is IEnumerable<Customer> with count 1000 or less
}
public static IEnumerable<IEnumerable<T>> GetPages<T>(this IEnumerable<T> source, int pageSize)
{
int i = 0;
IEnumerable<T> page = null;
while (page == null || page.Count() == pageSize)
{
page = source.Skip(i).Take(pageSize);
i += pageSize;
yield return page;
}
}