【问题标题】:How is it possible for a LINQ provider to transform arbitrary code?LINQ 提供程序如何转换任意代码?
【发布时间】:2014-06-26 10:04:12
【问题描述】:

我了解 LINQ 提供程序是将实际 LINQ 查询转换为 SQL 查询(或其他)的“东西”。它通过遍历 LINQ 查询的 AST 并呈现适当的 SQL 查询来实现。到目前为止,一切顺利。

现在我可以想象这适用于简单的 C# 代码,例如

where person.Age >= 18

可以(大部分直接)翻译成 SQL。但是如果我提供任意复杂的 C# 代码,例如:

where person.Name.StartsWith(person.Age < 25 ? 'X' : 'Y')

在 SQL 中没有与此等效的,那么 LINQ 提供程序在这种情况下会做什么?

【问题讨论】:

  • 它只是一个简单的case... when...,在 Sql 中带有一个like 'xxx%'...您可以查看生成的代码以了解它是如何翻译的。
  • SQL 中有一个等价物:CASE/WHEN in HAVING(即使对于更复杂的表达式)。也就是说,如果 LINQ 无法将该代码转换为 SQL,那么它只会抛出异常......
  • 您不能插入任何方法。如果无法翻译表达式树,它将失败。
  • 由于您询问的是自定义 linq 提供程序,因此很难说“它”在特定场景中会做什么。但是大多数提供者都会抛出异常。另一种方法是删除它不理解的约束(在 WHERE 子句的情况下),并在内存中评估这些约束(使用 linq 2 对象)
  • 基本上它不能转换任意代码,但它可以转换所有被告知的代码,以任何你愿意提供的组合。如果它没有被告知某段代码,它只会抛出某种错误(或者它可能会忽略它,或者坦率地说它可以做任何它想做的事情,但人们希望它会抛出一个异常)。

标签: c# .net linq custom-linq-providers


【解决方案1】:

在 SQL 中没有等价的

不确定它会如何实际编写 SQL(您可以对其进行测试),但可能很简单:

where person.Name like (case when person.Age < 25 then 'X' else 'Y' end) + '%'

要获得实际 SQL(假设它有效):分析连接。

但确实如此;并非所有事情都是可能的,并且通常它会简单地抛出一个异常以表明它无法识别某些东西或无法构造 SQL。例如,如果你这样做:

where person.Name.StartsWith(MyCustomMethod(person) ? 'X' : 'Y')

那么我预计它会失败。

【讨论】:

    【解决方案2】:

    使用CASE 表达式来渲染三元运算符似乎并不麻烦。

     CASE WHEN Person < 25 THEN 'X' ELSE 'Y' END
    

    否则,您会得到一个异常,指示您不要在 Linq To SQL 查询中使用方法调用。我认为 StartsWith 是受支持的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多