【问题标题】:Retrieving 10 records at a time only using LINQ一次仅使用 LINQ 检索 10 条记录
【发布时间】:2013-12-11 20:09:06
【问题描述】:

我目前正在研究 kendoUI 网格的服务器端分页和数据调用。我可以让网格执行服务器端事务,但我注意到即使全选或选择前 10 个,对 SQL 数据库的读取也是相同的。

当返回所有记录时 - 它会读取 104 的 sql profiler 当只返回 10 条记录时 - 它的 sql profiler 读取也为 104

用于返回数据的函数

public List<Employee> GetEmployees(int take, int skip)

{

return GetRepo<Employee>().All(null).where(p => p.IsDeleted == false).OrderBy(p => p.EmployeeNumber).Skip(10).Take(10).ToList();

}

当 LINQ 执行 10 条记录调用时,我使用了内置的 .Skip() 和 .Take() 函数。此方法需要 .OrderBy() 函数才能工作,并且我按表格上的 Id 列排序。

当您使用 .Skip() 和 .Take() 函数时,它会在用于一次调用所有记录的同一查询的外部包装前 10 个。请查看从 sql profiler 中提取的 sql 提取,

SELECT TOP (10) *
FROM ( SELECT *, row_number() OVER (ORDER BY [Project1].[EmployeeNumber] ASC) AS [row_number]
FROM ( SELECT 
[Extent1].[Id]
AS [Id], 
[Extent1].[FirstName]
AS [FirstName], 
[Extent1].[LastName]
AS [LastName], 
[Extent2].[EmployeeNumber]
AS [EmployeeNumber], 
[Extent2].[WeeklyHours]
AS [WeeklyHours], 
'0X0X'  AS [C1]

FROM [dbo].[Person]
AS [Extent1]
INNER JOIN  [dbo].[Employee] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Id]
WHERE 0 = [Extent2].[IsDeleted]
)  AS [Project1]
)  AS [Project1]
WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[EmployeeNumber] ASC

该项目是一个 asp.net MVC 项目并使用框架 4.5。

有没有办法在不必扫描整个表的情况下返回 10 条记录?随着员工和人员表随时会增长到超过 100 万条活动记录。

如果这属于错误的类别,我很抱歉。

任何帮助将不胜感激。

谢谢。

【问题讨论】:

    标签: asp.net-mvc linq entity-framework linq-to-sql linq-to-entities


    【解决方案1】:

    尝试使用 IQueryable 或 IEnumerable,而不是使用 List。下面是一个例子:

    public IQueryable<Employee> GetEmployees(int take, int skip)
    {
       return GetRepo<Employee>().All(null).where(p => p.IsDeleted == false).OrderBy(p => p.EmployeeNumber).Skip(10).Take(10);
    }
    

    注意:

    IQueryable 旨在允许查询提供程序(例如,像 LINQ to SQL 或实体框架这样的 ORM)使用 查询中包含的表达式,用于将请求转换为另一个 格式。换句话说,LINQ-to-SQL 会查看 您正在使用的实体以及您正在进行的比较 并且实际上创建了一个 SQL 语句来表达(希望) 等效请求。

    IEnumerable 比 IQueryable 更通用(尽管 IQueryable 的所有实例都实现 IEnumerable)并且只定义 一个序列。但是,在 在其上定义一些查询类型运算符的可枚举类 接口并使用普通代码来评估这些条件。

    List 只是一种输出格式,虽然它实现了 IEnumerable,但与查询没有直接关系。

    更多详情,请查看以下链接:

    Differences between IQueryable, List, IEnumerator?

    更新

    如果您在 IRepository 接口类中定义了一个过滤器,如下所示

    IQueryable<T> Filter(Expression<Func<T, bool>> filter);
    

    您可以更改 GetEmployees 方法,如下所示:

    public IQueryable<Employee> GetEmployees(int take, int skip)
    {
       return GetRepo<Employee>().Filter(p => p.IsDeleted == false).OrderBy(p => p.EmployeeNumber).Skip(10).Take(10);
    }
    

    原因是让查询延迟。

    【讨论】:

    • 感谢@Lin 的建议。我已经尝试过 IQueryable 和 IEnumerable 但生成的 SQL 仍会扫描整个表并获取所需的内容。即使在 sql server management studio 中创建 sql 脚本并使用 'rank() over(Order by)' 函数时,读取的次数也是相同的。
    • 嗨@pchannon,GetRepo().All()的返回类型是什么,如果是List,需要改成IQqueryable。
    • GetRepo()的返回类型是IRepository。请在public static IRepository&lt;T&gt; GetRepo&lt;T&gt;() where T : class { var factory = new PayrollRepositories&lt;T&gt;(); return factory.GetRepository(); }下方输入一点代码sn-p@
    • 我猜你应该检查 IRepository 中的“All”方法定义。它应该看起来像“IQueryable All()”。我也确定你为什么要返回静态 IRepository.
    • 感谢@Lin 的帮助。我找到了一种方法,通过在调用中添加 .AsQueryable 来使用原始语句来降低对数据库的读取。例如return GetRepo&lt;Employee&gt;().All(null).AsQueryable().where(p =&gt; p.IsDeleted == false).OrderBy(p =&gt; p.EmployeeNumber).Skip(10).Take(10).ToList();。这将读取次数从 104 降低到 6。这将节省未来的数据库负载。
    猜你喜欢
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多