【问题标题】:How to conveniently rewrite LINQ query?如何方便地重写 LINQ 查询?
【发布时间】:2014-05-07 14:55:20
【问题描述】:

我发现 SQL Server 无法有效处理一些基本的 SQL 查询,例如:

SELECT TOP (1) [t0].[Id], [t0].[L1], [t0].[L2], [t0].[Value]
FROM [Foos] AS [t0]
INNER JOIN [Lookup1] AS [t1] ON [t1].[Id] = [t0].[L2]
INNER JOIN [Lookup2] AS [t2] ON [t2].[Id] = [t0].[L1]
WHERE ([t1].[Name] = 'a') AND ([t2].[Name] = 'b')
ORDER BY [t0].[Value]

由 LINQ 表达式生成:

// query 1

Foos
.Where(f => f.Lookup1.Name == "a" && f.Lookup2.Name == "b")
.OrderBy(f => f.Value)
.Take(1)

架构定义存在问题“Index over multiple lookup tables in SQL Server”。答案中的@Hoots 表明 SQL 查询必须如下所示:

SELECT TOP (1) [t0].[Id], [t0].[L1], [t0].[L2], [t0].[Value]
FROM [Foos] AS [t0]
CROSS JOIN (
    SELECT TOP (1) [t1].[Id], [t2].[Id] AS [Id2]
    FROM [Lookup1] AS [t1], [Lookup2] AS [t2]
    WHERE ([t1].[Name] = 'a') AND ([t2].[Name] = 'b')
    ) AS [t3]
WHERE ([t0].[L1] = [t3].[Id]) AND ([t0].[L2] = [t3].[Id2])
ORDER BY [t0].[Value] DESC

可以从以下 LINQ 表达式生成:

// query 2

(from f in Foos
from l in (
    from l1 in Lookup1s
    from l2 in Lookup2s
    where l1.Name == "a"
        && l2.Name == "b"
    select new { L1 = l1.Id, L2 = l2.Id }).Take(1)
where f.L1 == l.L1 && f.L2 == l.L2
orderby f.Value descending
select f).Take(1)

我的问题是如何自动将查询 1 重写为查询 2?所以我可以分多个步骤编写查询:

void Do()
{
    var x = ListFoos("a", "b").OrderBy(f => f.Value).Take(2);
    // ...
}

IQueryable<Foos> ListFoos(string l1, string l2)
{
    var foos = Foos.AsQueryable();
    if (l1 != null)
        foos = foos.Where(f => f.Lookup1.Name == l1);
    if (l2 != null)
        foos = foos.Where(f => f.Lookup2.Name == l2);
    return foos;
}

有人已经这样做了吗?是否有简化任务的库?

澄清:

IQueryable&lt;&gt; 的结果表达式被转换为 SQL Server 无法有效评估的 SQL 语句。所以我需要将表达式转换为一个表达式,该表达式被转换为 SQL Server 的更好的 SQL 语句。

我想我不是第一个遇到这个问题的人。 LINQ 在这里的时间较长,而且 SQL 语句非常基础,因此其他开发人员可能已经在使用 SQL Server 解决了这个问题。

【问题讨论】:

  • 我需要在运行时进行。所以我可以重写在多个函数调用中形成的查询。 (l1 和 l2 是用户提供的变量。)
  • 没有自动的方法,但是当你说SQL Server is unable efficiently process some basic SQL queries时,我不知道你为什么会得出这个结论

标签: c# .net sql-server linq entity-framework


【解决方案1】:

我不能 100% 确定我知道您的要求,但如果我是对的,您应该查看 PredicateBuilder。它非常有用。链接在这里:

http://www.albahari.com/nutshell/predicatebuilder.aspx

它是 LinqKit 的一部分:

http://www.albahari.com/nutshell/linqkit.aspx

这里有一些关于如何使用它的信息:

How does PredicateBuilder work

它基本上会让你做这样的事情:

var predicate = PredicateBuilder.True<Foo>();
            if (l1 != null)
                predicate = predicate.And(f => f.Lookup1.Name == l1);
            if (l2 != null)
                predicate = predicate.Or(f => f.Lookup2.Name == l2);

            return Foos.Where(predicate);

请注意以上内容来自记忆..我没有测试过这个...所以可能有一些错别字...

【讨论】:

  • “我不是 100% 确定我知道你要什么”。所以要求澄清。你的答案是错误的。
  • @GertArnold:感谢您的评论,但 OP 的话是“所以我可以分多个步骤编写查询”,然后最终的代码示例似乎表明我的结论是正确的。也许我错了。 TN,请随时澄清
  • 在我看来,OP 正在寻找一种自动化的方式来将查询塑造成产生更好 SQL 的形式,以便他可以先编写查询,然后再重新塑造它们。主要是关于重塑。但问你是否不确定。
  • @GertArnold 是对的。我有一个IQueryable&lt;&gt;,它生成 SQL Server 无法有效评估的 SQL。所以我正在寻找一个库来帮助我翻译 IQueryable&lt;&gt;'s 表达式,从而产生更好的 SQL。
猜你喜欢
  • 2016-02-08
  • 1970-01-01
  • 1970-01-01
  • 2011-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
  • 1970-01-01
相关资源
最近更新 更多