I have a LINQ query to retrieve the maximum value of an integer column. The column is defined as NOT NULL in the database. However, when using the MAX aggregate function in SQL you will get a NULL result if no rows are returned by the query.
Here is a sample LINQ query I am using against the Northwind database to demonstrate what I am doing.
var maxValue = (from p in nw.Products
where p.ProductID < 0
select p.ProductID as int?).Max();
C# correctly parses this query and maxValue has a type of int?. Furthermore, the SQL that is generated is perfect:
SELECT MAX([t0].[ProductID]) AS [value]
FROM [Products] AS [t0]
WHERE [t0].[ProductID] < @p0
The question is, how do I code this using VB.NET and get identical results? If I do a straight translation:
dim maxValue = (from p in Products
where p.ProductID < 0
select TryCast(p.ProductID, integer?)).Max()
I get a compile error. TryCast will only work with reference types, not value types. TryCast & "as" are slightly different in this respect. C# does a little extra work with boxing to handle value types. So, my next solution is to use CType instead of TryCast:
dim maxValue = (from p in Products
where p.ProductID > 0
select CType(p.ProductID, integer?)).Max()
This works, but it generates the following SQL:
SELECT MAX([t1].[value]) AS [value]
FROM (
SELECT [t0].[ProductID] AS [value], [t0].[ProductID]
FROM [Products] AS [t0]
) AS [t1]
WHERE [t1].[ProductID] > @p0
While this is correct, it is not very clean. Granted, in this particular case SQL Server would probably optimize the query it to be the same as the C# version, I can envisage situations where this might not be the case. Interestingly, in the C# version, if I use a normal cast (i.e. (int?)p.ProductID) instead of using the "as" operator I get the same SQL as the VB version.
Does anyone know if there is a way to generate the optimal SQL in VB for this type of query?