【问题标题】:When selected into an object; does Linq To SQL still perform the logic in a SQL Query?当被选入对象时; Linq To SQL 是否仍然执行 SQL 查询中的逻辑?
【发布时间】:2013-06-14 01:11:36
【问题描述】:

假设我有以下简化的 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,如果是,为什么会这样?

【问题讨论】:

  • 您是否尝试过运行分析器来检查执行的 SQL?它应该可以很好地表明 SQL 执行了多少。
  • "我希望在 Linq 中维护业务逻辑,以便轻松进行单元测试" 1) 无论 Linq 在您的客户端应用程序还是在 SQL 中执行,您的逻辑都是仍然在 Linq 中,所以,2) Linq 的任何选择都不应该对您的单元测试产生任何影响。
  • 直到您进行迭代或某事导致迭代,它仍在构造 SQL 语句。你应该没问题
  • @DarrenKopp,函数返回类型 IEnumerable 是否意味着它是退出 L2S 域并进入 L2O 域的点?我认为确实如此,因为 Linq to Sql 查询返回 IQueryable.
  • 是的,一旦你点击了 IEnumerable,你就处于 linq 2 对象中,这意味着一切都将在内存中完成,但只有在你开始迭代之后。

标签: c# linq linq-to-sql


【解决方案1】:

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

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

【讨论】:

  • 谢谢@evanmcdonnal;我使用集成测试来获取生成的 SQL 查询,它确实执行了 SQL 中的所有排序和不同操作。
【解决方案2】:

相信你发布的所有代码都会被转换成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 的好书。您将获得多次奖励。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多