【问题标题】:LinqToSql - SQL generated by CONCAT (UNION)LinqToSql - 由 CONCAT (UNION) 生成的 SQL
【发布时间】:2014-07-04 17:30:05
【问题描述】:

简单地说,有没有办法强制LinqToSql 生成链式连接而不嵌套UNION ALL 语句?

例子:

a.Concat(b).Concat(c)

导致语义上类似于:

SELECT * FROM (
    SELECT * FROM A
    UNION ALL 
    SELECT * FROM B
)
UNION ALL
SELECT * FROM C

如果我能说服它这样做,它会更具可读性/更可取:

SELECT * FROM A
UNION ALL
SELECT * FROM B
UNION ALL
SELECT * FROM C

我明白它为什么会这样做(我什至不确定这两件事在语义上是否完全相同)但是有什么办法可以做到这一点?这将使我们生成的一堆查询变得更容易阅读和调试。

【问题讨论】:

  • 查看两者的执行计划,手动运行它们。
  • 我对性能、结果或执行计划没有疑虑。我的问题是可读性。我想知道如何使用 LINQ 从集合 A、B 和 C 生成第二个 SQL 块。
  • 如果性能或执行计划没有问题,为什么会对生成的SQL感兴趣。毕竟,这就是抽象层的全部意义所在。除非有问题,否则没有人应该阅读它。
  • 简单:因为总会有问题,总要有人阅读。事实上,这是一种常见的需求,当您在 Visual Studio 中将鼠标悬停在 IQueryable 变量上时,您会得到生成的 SQL! (另外,如果你只是在拖钓,玩得很好。)

标签: c# tsql linq-to-sql


【解决方案1】:

从 LINQ 生成的 SQL 并不是为了可读而设计的,所以我认为没有办法做到这一点。这会很好,我同意。这也是我对 Dapper 这样的微 ORM 概念感兴趣的原因之一,因此我可以编写自己的 SQL。

【讨论】:

    【解决方案2】:

    我在连接大量自动生成的 iqueryables 时遇到了问题,因为生成的 sql 查询的嵌套行为太深而无法处理。我通过以类似二叉树的方式连接项目来解决它,如下所示:

    public static IQueryable<T> BinaryConcatenation<T>(this IEnumerable<IQueryable<T>> queries)
    {
        var count = queries.Count();
        var firsthalf = queries.Take(count / 2).ToArray();
        var secondhalf = queries.Skip(count / 2).ToArray();
        if (firsthalf.Length == 0 || secondhalf.Length == 0) return queries.Aggregate((src, next) => src.Concat(next));
    
        var first = BinaryConcatenation(firsthalf);
        var second = BinaryConcatenation(secondhalf);
        return first.Concat(second);
    }
    

    这样生成的 SQL 嵌套深度会大大降低(log(n)?)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-19
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-12
    • 2010-09-24
    • 2017-03-13
    相关资源
    最近更新 更多