我一直在尝试解决 VB.NET 和它喜欢生成的表达式树的一个小问题。
我有一个简单的测试...
Public Sub ActiveRecord_Find_By_NonKey_Returns_123()
Dim orders = Order.Find(Function(item As Order) item.EmployeeID = 1)
Assert.Equal(Of Integer)(123, orders.Count)
End Sub
人们会期望它可以工作,但该item.EmployeeID = 1
位存在问题,这只是 VB.NET 的问题,而不是 C# 的问题。VB.NET 喜欢巧妙地使用它编译的表达式树,因为它可以item.EmployeeID
为空!(阅读与此相关的博客)
问题是表达式被表达式节点item.EmployeeID = 1
包裹。Convert
此时 TSql 生成器完全丢失并创建以下WHERE
子句。
WHERE ([t0].[EmployeeID] = 1) <> 0
该片段在数据库上执行时往往会失败。
所以这似乎是 SubSonic 中的一个错误。不幸的是,试图弄清楚如何/在哪里修复它让我很头疼!
不过它确实变得更有趣了。
Public Sub ActiveRecord_Find_By_NonKey_Returns_123_Linq()
Dim orders = From item In Order.All Where item.EmployeeID = 1 Select item
Assert.Equal(Of Integer)(123, orders.Count)
End Sub
但它的WHERE
条款是...
WHERE COALESCE(CASE WHEN (([t0].[EmployeeID] = 1)) THEN 1 ELSE 0 END, 0) <> 0
好吧,这似乎不是最理想的!但至少它有效。
最后,在阅读了博客条目后,似乎可以解决上面的原始示例。在 VB.NET 中使用新的合并运算符 (If)...
Public Sub ActiveRecord_Find_By_NonKey_Returns_123_Fix()
Dim orders = Order.Find(Function(item As Order) If(item.EmployeeID, 0) = 1)
Assert.Equal(Of Integer)(123, orders.Count)
End Sub
这产生了这个WHERE
条款......
WHERE (COALESCE([t0].[EmployeeID], 0) = 1)
一个稍微更简洁的查询,尽管使用ISNULL
与COALESCE
? 也许只是在跨 SQL 版本的兼容性方面。
基本上,我希望第一个示例按原样工作。我还希望第二个示例继续工作,但生成更清晰的 SQL。
我想自己解决这个问题,但除了意识到我在 VB.NETs 表达式树生成方面存在一些问题之外,还没有走得太远。