views:

420

answers:

0

I've been trying to solve a little problem with VB.NET and the expression trees it likes to generate.

I have a simple test...

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

One would expect that to work but there is a problem with the item.EmployeeID = 1 bit and it is only a problem for VB.NET and not C#. VB.NET likes to be clever with the expression tree it compiles because of the fact item.EmployeeID is nullable! (Read blog relating to this)

The problem is that expression item.EmployeeID = 1 gets wraps with a Convert expression node. At which point the TSql generator gets completely lost and creates the following WHERE clause.

WHERE ([t0].[EmployeeID] = 1) <> 0

That snippet tends to fail somewhat when it is executed on the database.

So that seems to be a bug in SubSonic. Unfortunately trying to work out how/where to fix it is doing my head in!


It does get more interesting though.

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

But its WHERE clause is...

WHERE COALESCE(CASE WHEN (([t0].[EmployeeID] = 1)) THEN 1 ELSE 0 END, 0) <> 0

Well that seems sub-optimal! But at least it works.

Finally, there seems to be a work around for the original example above after reading the blog entry. Use the new coalesce operator (If) in VB.NET...

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

Which produces this WHERE clause...

WHERE (COALESCE([t0].[EmployeeID], 0) = 1)

A slightly more concise query though it there a difference between using ISNULL as opposed to COALESCE? Perhaps only in terms of compatibility across versions of SQL.


Basically, I want the first example to work as it is. I'd also like the second example to keep working but produce much cleaner SQL.

I would like to fix this myself but haven't gotten very far other than realise I have some issues with VB.NETs expression tree generation.