私は、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# の問題ではありません。item.EmployeeID
VB.NET は、 null 許容であるため、コンパイルする式ツリーを賢く使用するのが好きです! (これに関連するブログを読む)
問題は、式が式ノード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 のバージョン間の互換性に関してのみです。
基本的には、最初の例をそのまま動作させたいと思っています。また、2 番目の例が機能し続け、よりクリーンな SQL が生成されるようにしたいと考えています。
私はこれを自分で修正したいと思っていますが、VB.NET 式ツリーの生成に問題があることを認識する以外に、あまり進んでいません。