views:

99

answers:

1

I have a DataContext object, called "CodeLookupAccessDataContext", that was generated through the Visual Studio LINQ to SQL class wizard. I extended the functionality of this object such that it exposes some methods to return results of LINQ to SQL queries. Here are the methods I have defined:

public List<CompositeSIDMap> lookupCompositeSIDMap(int regionId, int marketId)
{
    var sidGroupId = CompositeSIDGroupMaps.Where(x => x.RegionID.Equals(regionId) && x.MarketID.Equals(marketId))
        .Select(x => x.CompositeSIDGroup);

    IEnumerator<int> sidGroupIdEnum = sidGroupId.GetEnumerator();

    if (sidGroupIdEnum.MoveNext())
        return lookupCodeInfo<CompositeSIDMap, CompositeSIDMap>(x => x.CompositeSIDGroup.Equals(sidGroupIdEnum.Current), x => x);
    else
        return null;
}

private List<TResult> lookupCodeInfo<T, TResult>(Func<T, bool> compLambda, Func<T, TResult> selectLambda)
    where T : class
{
    System.Data.Linq.Table<T> dataTable = this.GetTable<T>();

    var codeQueryResult = dataTable.Where(compLambda)
        .Select(selectLambda);

    List<TResult> codeList = new List<TResult>();
    foreach (TResult row in codeQueryResult)
        codeList.Add(row);

    return codeList;
}

CompositeSIDGroupMap and CompositeSIDMap are both tables in our database that are represented as objects in my DataContext object. I wrote the following code to call these methods and display the T-SQL generated after calling these methods:

using (CodeLookupAccessDataContext codeLookup = new CodeLookupAccessDataContext())
{
    codeLookup.Log = Console.Out;
    List<CompositeSIDMap> compList = codeLookup.lookupCompositeSIDMap(regionId, marketId);
}

I got the following results in my log after invoking this code:

SELECT [t0].[CompositeSIDGroup]
FROM [dbo].[CompositeSIDGroupMap] AS [t0]
WHERE ([t0].[RegionID] = @p0) AND ([t0].[MarketID] = @p1)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [5]
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [3]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.1

SELECT [t0].[PK_CSM], [t0].[CompositeSIDGroup], [t0].[InputSID], [t0].[TargetSID], [t0].[StartOffset], [t0].[EndOffset], [t0].[Scale]
FROM [dbo].[CompositeSIDMap] AS [t0]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.1

The first T-SQL statement contains a where clause as specified and returns one column as expected. However, the second statement is missing a where clause and returns all columns, even though I did specify which rows I wanted to view and which columns were of interest. Why is the second T-SQL statement generated the way it is, and what should I do to ensure that I filter out the data according to specifications via the T-SQL?

Also note that I would prefer to keep lookupCodeInfo() and especially am interested in keeping it enabled to accept lambda functions for specifying which rows/columns to return.

UPDATE

This discussion might also be of interest.

+3  A: 

The problem is that the function

private List<TResult> lookupCodeInfo<T, TResult>(Func<T, bool> compLambda, 
                                                 Func<T, TResult> selectLambda)

accepts Func<...> arguments, which will make the lambdas compiled into functions. The Linq-to-sql SQL generator cannot translate a compiled function to SQL, but will rather perform the filtering and projection in memory.

Change your lookupCodeInfo to take Expression<...> instead, which will preserve them as expression trees that linq-to-sql can traverse.

Anders Abel
More importantly, LINQ-to-SQL *is never asked* to do this; by giving it a `Func<>` you are using `Enumerable.Where`, not `Queryable.Where`, and hence switching to LINQ-to-Objects. So it isn't *quite* just that "it can't" (although you are right: it can't)
Marc Gravell
Thanks for the helpful tips and especially the explanation regarding what was going on (which is really what I was looking for). When using LINQ to Objects I had to compile my expressions. I assumed that the same applied to LINQ to SQL, which explains my confusion.
Jimmy W