3

假设我有以下简化的 Linq 查询,它将使用 LinqToSQL 对数据库运行:

public IEnumerable<MembershipDto> GetAllUserMemberships()
{
    return (from m in _workspace.GetDataSource<UserMembership>()
            join g in _workspace.GetDataSource<Group>()
                on m.GroupID equals g.GroupID
            join u in _workspace.GetDataSource<User>()
                on m.UserID equals u.UserID
            select 
                new MembershipDto
                {
                    GroupID = g.GroupID,
                    GroupName = g.Name,
                    UserID = u.UserID,
                    UserName = u.Name
                }
            ).Distinct()
             .OrderBy(x => x.GroupName)
             .ThenBy(x => x.UserName);
}

出于性能考虑,我希望尽可能多地在生成的 SQL 查询中运行此查询;但是我希望在 Linq 中维护业务逻辑,以便轻松进行单元测试。

我遇到的问题是我不确定上述查询在 SQL 中停止执行并开始在内存中进行操作的位置。

我的假设是,一旦数据被选入,new MembershipDto它就不再在 SQL 中执行;因此后续的OrderBy() ThenBy()Distinct()操作发生在内存中。

然而,OrderBy()产生一个类型的集合IOrderedQueryable而不是一个IOrderedEnumerable; 这向我表明该查询仍然可以在 SQL 中完整执行。

我的假设是否正确,或者整个查询是否已转换为 SQL,如果是,为什么会这样?

4

2 回答 2

3

只需查看生成的 SQL。我相当有信心您的斜体假设是错误的。LINQ to SQL 提供程序将识别您的OrderBy,ThenByDistinct操作仅在 SQL 结果上执行,因此它会在您选择的行上完成这些操作,然后再将它们反序列化为对象。如果您尝试操作在执行时对数据库不可用的值,则该部分查询只会由 LINQ to Objects 执行。

如果在初始化程序中将某些属性设置为查询结果中不可用的值,那么在OrderBy子句中使用它肯定会在内存中进行排序,因为没有其他方法。在这种情况下,您的 select 被翻译成 SQL SELECT,然后像通常OrderBy那样Distinct被调用。将您的选择转换为对象是一个完全独立于选择数据库中的列的操作。对于 SQL 提供者,您的查询与简单的选择语句没有什么不同,它构建一个表达式树并在执行时将它可以转换的任何内容转换为 SQL。

于 2013-06-13T16:26:05.060 回答
1

相信您发布的所有代码都会转换为sql。MembershipDto() 构造将映射到一个 select 语句。

当您的函数强制转换为 IEnumerable 并执行枚举器时,您将“退出”Linq to Sql 并“输入”Linq to Objects。

如果您在 Linq to Sql 中进行开发,那么您必须拥有自己测试的工具。

我推荐LINQPad。您使用 C# 编写代码,它会向您显示生成的 SQL。

另一种解决方案是在数据上下文中记录生成的 SQL:

#if DEBUG
        /// <summary>
        /// Code which runs when the data context is created; called from the constructor
        /// </summary>
        /// <remarks>Adds console and/or ASP.NET trace logger in DEBUG builds only</remarks>
        partial void OnCreated()
        {
            this.DebugBuildLogging();
        }
#endif

我还建议阅读一本关于 LINQ 的好书。您将获得多次奖励。

于 2013-06-13T16:56:31.923 回答