【问题标题】:Subsonic 3.0.0.3 SQL Paging using Linq使用 Linq 的 Subsonic 3.0.0.3 SQL 分页
【发布时间】:2009-08-31 21:20:48
【问题描述】:

刚刚从 Subsonic 2.2 ActiveRecord 更新到 3.0.0.3。我正在尝试使用 LINQ 执行这样的分页查找查询(我的对象/表称为“存储库”):

Repository.Find(item => item.DocumentTitle.Contains(searchTerm))
    .OrderBy(i => i.DocumentTitle).Skip((currentPage - 1) * itemsPerPage)
    .Take(itemsPerPage);

当我使用 SQL Server Profiler 查看此查询生成的 SQL 时,SQL 中没有分页,所有分页都在 C# 的内存中完成。现在,Subsonic 查询语言确实有一个很好的 GetPaged 过程,它确实可以正常工作,但我认为 LINQ 也应该这样做。我在这里遗漏了什么还是这是 LINQ 的限制?

我知道 Repository.GetPaged() 函数,但它没有足够的参数 - 我需要进行动态排序以及 Find()

【问题讨论】:

    标签: linq subsonic subsonic3 paging


    【解决方案1】:

    经过进一步测试,此语句正常工作:

    (from i in dataContext.Repositories 
     where i.DocumentTitle.Contains(searchTerm) 
     orderby i.DateCreated ascending select i)
     .Skip((currentPage - 1) * itemsPerPage).Take(itemsPerPage);
    

    当执行时,上面的 linq 语句在 sql 中正确分页返回。

    我能得出的唯一结论是,当您使用方法链接语法时,一旦您超出了初始 lamda 表达式

    Repository.Find(item => item.DocumentTitle.Contains(searchTerm))
    

    亚音速 SQL 解释器停止为最后链接的任何方法创建 SQL

    .OrderBy(i => i.DocumentTitle).Skip(15).Take(10);
    

    或者,我只是在这里完全做错了吗?有人有什么见解吗?

    【讨论】:

    • 做了更多的研究。显然,这是由于 C# 如何编译 linq 表达式。编译器必须在设计时知道该语句将是什么。如果不是,则该语句无法由 SubSonic“ExpressionVisitor”(这不是 SubSonic 独有)反映,因为它不再是单个“Expression”。
    • 有第三方库可以让你在多个步骤中构建你的 linq 语句,但这会给你的项目增加更多的外部依赖。 SubSonic 实际上似乎已经具备其中的一些功能,但我目前还不够了解,所以建议一种使用它们来完成此功能的方法。
    【解决方案2】:

    您可以通过在排序字段中添加“desc”来对 GetPaged 进行排序,但是...

    分页应该可以工作 - 我正在查看我面前的分页 SQL,但它并没有在内存中完成。你如何测试这个?如果您使用将执行查询的“ToList()” - 那么请查看分析器。

    【讨论】:

    • GetPaged 函数将是理想的,但我还需要它来执行 Find()。所以 FindGetPaged() 如果你愿意的话。这是我从发布的查询中看到的 SQL(我还尝试了 ToList(),我一直将 IEnumerable 传递给 ListView 数据源):exec sp_executesql N'SELECT [t0].[CategoryName], [ t0].[DateCreated], [t0].[DocumentFileType], [t0].[DocumentTitle], [t0].[FileContent], [t0].[RepositoryId] FROM [dbo].[mag_Repository] ​​AS t0 WHERE ( [t0].[DocumentTitle] LIKE ''%'' + @p0 + ''%'')',N'@p0 nvarchar(4000)',@p0=N''
    • 为了测试它,我附加了 VS 调试器,仅为我的数据库启动了分析器,然后在这个函数处中断: List retList = Repository .Find(item => item.DocumentTitle.Contains (searchTerm)) .OrderByDescending(i => i.DocumentTitle) .Skip((currentPage - 1) * itemsPerPage) .Take(itemsPerPage).ToList();当我按下 F10 时,观察 sql 语句通过配置文件。
    • 我还对 GetPaged 进行了测试,以确保我看到的 SQL 是正确的,并且它通过 RowNumber() 分页 sql 语句正确完成。所以我不知道我在这里做错了什么。
    【解决方案3】:

    有点晚了,但是……

    Repository.Find()
    

    返回 IList 以便执行查询,因此 SQL 执行时无需分页

    .Skip(x).Take(x)
    

    在内存中完成。 试试

    Repository.All().Where(expression).Skip(x).Take(x)
    

    所有这些都返回 IQueryable 而不是枚举对象,因此分页是在 SQL 中使用 ROW_NUMBER() 函数完成的。

    话虽如此,Subsonic 3 简单存储库正在生成以下 SQL

    exec sp_executesql N'SELECT [t0].[Id], [t0].[IsDeleted], [t0].[Name], [t0].[ParentUuid], [t0].[Uuid]
    FROM ( SELECT [t1].[Id], [t1].[IsDeleted], [t1].[Name], [t1].[ParentUuid], ROW_NUMBER() OVER() AS rownum, [t1].[Uuid]
    FROM [Sites] AS t1
    WHERE (([t1].[ParentUuid] = @p0) AND ([t1].[IsDeleted] = 0))) AS t0
    WHERE [t0].[rownum] BETWEEN (20 + 1) AND (20 + 10)',N'@p0 uniqueidentifier',@p0='00000000-0000-0000-0000-000000000000'
    

    抛出异常

    Unhandled Exception: System.Data.SqlClient.SqlException: The ranking function "ROW_NUMBER" must have an ORDER BY clause.
    

    所以看起来 Subsonic 有一个错误:-(

    【讨论】:

    • 我不会说这是一个 SubSonic 错误,因为 SubSonic 会将您的查询转换为纯 sql。由于异常告诉你 ROW_NUMBER 必须有一个 ORDER BY 子句,你必须在你的 linq 查询中添加一个 orderby 关键字,所以 subsonic 也会生成一个 order by(顺便说一句。mysql 在这种情况下不会抛出异常,因为 LIMIT(x ,y) 不需要 ORDER BY
    • 也许不是错误,同意。我已经更新了 subsonic 的本地构建,以测试是否已将 order by 子句添加到包含 ROW_NUMBER 函数的任何查询中,如果没有 order by,我将 ORDER BY Id 插入 ROW_NUMBER 的 OVER 部分,从而避免异常。这并不理想,而且是特定于环境的(我的所有 DOM 类都必须继承 DomBase 并且将具有 ID 属性)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 2010-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多