views:

162

answers:

0

I’ve two issues that I was hoping for some insight on and/or some appropriate links or Google terms to use to find more information on as I’m not finding anything. It boils down to the fact that I would like to find out when/how an IQueryable expression that is going to be executed determines that some of the expression result needs to be run ‘client side’, meaning that the LINQ expression cannot be translated directly to Transact SQL to return the entire result.

This is in regards to my post/code: http://www.aneyfamily.com/terryandann/post/2008/04/Batch-Updates-and-Deletes-with-LINQ-to-SQL.aspx

If you have any suggestions, I would greatly appreciate it.

Situation 1

string.Format() does not translate to Transact SQL. I can accept that, but guess I was just looking for some advice on how to detect if an Expression will be able to fully translate to Transact SQL.

LINQ Expression:

from h in HistoryData
select new { NewData = string.Format( "New Data: {0}", h.hisData ) };

Provider Context SQL:

SELECT [t0].[hisData] AS [arg0]
FROM [HistoryData] AS [t0]

My Workaround: Currently, I’m using DataContext.GetCommand() method then looking at the Transact SQL and searching for [arg0]. Obviously not ideal, so I was looking for a more robust mechanism (possibly spotting something with an ExpressionTree visitor??)

Situation 2

Using the tertiary operator in some situations seems to return some Transact SQL that obviously has some post/client processing applied to it to get the proper values. In the examples below, I’m running within the context of LINQPad (thus the Dump() extension method is available). There seems to be two situations when post processing is needed when a tertiary operator is in play; a) when a boolean variable along with a boolean field is used (var testBool… expression below) and b) when two variables, regardless of type, are used and no database fields are queried (the second testNumber expression below).

This situation surprised me that client side processing was needed. So in addition to learning how to properly detect when an expression needs additionally processing outside of the normal Transact SQL, if anyone has any insight as to why L2S couldn’t execute a simple CASE statement like the other situations and more importantly a possible workaround that could be used to avoid any ‘client side’ processing that would be great!

LINQ Expressions:

var before9_1_2009 = DateTime.Today < new DateTime( 2009, 9, 1 );
var fiveThousand = 5000;
var tenThousand = 10000;
var testNumber = 
    Profiles.Where( p => p.pAuthID == "111111111" )
            .Select( p => new { Number = before9_1_2009 ? fiveThousand : p.pKey } );
var cmd = GetCommand( testNumber );
cmd.CommandText.Dump( "Number Property: Works (i.e. evaluates on SQL Server)" );

var testString = 
    Profiles.Where( p => p.pAuthID == "111111111" )
            .Select( p => new { String = before9_1_2009 ? "StringConstant" : p.pAuthID } );
cmd = GetCommand( testString );
cmd.CommandText.Dump( "String Property: Works (i.e. evaluates on SQL Server)" );

var testBool = 
    Profiles.Where( p => p.pAuthID == "111111111" )
            .Select( p => new { Boolean = boolExp ? true : p.pProcessed } );
cmd = GetCommand( testBool );
cmd.CommandText.Dump( "Boolean Property: Has NULL AS [EMPTY] - Post Processing Needed" );

testNumber = 
    Profiles.Where( p => p.pAuthID == "111111111" )
            .Select( p => new { Number = before9_1_2009 ? fiveThousand : tenThousand } );
cmd = GetCommand( testNumber );
cmd.CommandText.Dump( "Number Property (using two constants): Has NULL AS [EMPTY] - Post Processing Needed" );

Provider Context SQL (in order): ▪ Number Property: Works (i.e. evaluates on SQL Server)

SELECT 
    (CASE 
        WHEN @p1 = 1 THEN @p2
        ELSE [t0].[pKey]
     END) AS [Number]
FROM [Profile] AS [t0]
WHERE [t0].[pAuthID] = @p0

▪ String Property: Works (i.e. evaluates on SQL Server)

SELECT 
    (CASE 
        WHEN @p1 = 1 THEN CONVERT(NVarChar(255),@p2)
        ELSE [t0].[pAuthID]
     END) AS [String]
FROM [Profile] AS [t0]
WHERE [t0].[pAuthID] = @p0

▪ Boolean Property: Has NULL AS [EMPTY]

SELECT NULL AS [EMPTY]
FROM [Profile] AS [t0]
WHERE [t0].[pAuthID] = @p0

▪ Number Property (using two constants): Has NULL AS [EMPTY]

SELECT NULL AS [EMPTY]
FROM [Profile] AS [t0]
WHERE [t0].[pAuthID] = @p0

My Workaround: Again, I’m using DataContext.GetCommand() method then looking at the Transact SQL and searching for NULL AS [EMPTY]. Wondering if there are any other ‘magic strings’ that are going to appear for expression code that cannot run on the server…so as above, I’m looking for a correct, more robust way of detecting these situations.

Thanks again in advance.