1

私は、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.EmployeeIDVB.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 式ツリーの生成に問題があることを認識する以外に、あまり進んでいません。

4

0 に答える 0