1

I'm currently writing a wrapper object for a series of database result sets. In so doing, I've noticed a problem when querying with LINQ and Lambda expressions. Specifically, calling a method within the lambda seems to always make the result set empty and never actually fires the method I'm attempting to filter with. Here's the code:

' Query and filter container results 
Public Function [Filter](pFilter As IFilter(Of T)) As System.Linq.IQueryable(Of T)
    ' THIS YIELDS AN EMPTY SET EVEN WHEN pFilter.Test(o) ALWAYS RETURNS TRUE
    Dim lResult As System.Linq.IQueryable(Of T) = mTable.Where(Function(o As T) pFilter.Test(o))

    Return lResult
End Function

pFilter implements IFilter with this signature:

Public Interface IFilter(Of T)
    Function Test(ByVal pObject As T) As Boolean
End Interface

I've break pointed pFilter.Test(o) and found it is never actually called. Oddly enough, if I replace pFilter.Test(o) with True, I receive the entire table of records as expected. Also, I receive no compile time or run time errors in any case.

I'm pretty new to Lambdas and LINQ so fully recognize I may not understand the limits of what I am attempting to accomplish. Any help is greatly appreciated!

SOLUTION: I've marked a solution already as the author got me on the right track. The true nature of this problem stems from my attempting to force a .NET function into something LINQ could turn into an SQL statement (which is impossible). To solve this, I've changed my IFilter to return System.Linq.Expressions.Expression(Of Func(Of T, Boolean)) for the Test method. Now I can create strongly-typed filters which return predicates and pass them directly to Where() without the use of a lambda expression. I'm also using LinqKit to make this work more easily for those who may be accomplishing similar tasks.

Brian Webster
  • 30,033
  • 48
  • 152
  • 225
David Peterson
  • 728
  • 6
  • 17
  • Can you post some code we could use to reproduce your issue? – Victor Zakharov Oct 25 '12 at 17:59
  • How are you observing the empty set? You can't put a breakpoint in that spot to know if it calls the method, becuase at this point you're only building an expression tree. You have to put the breakpoint where you actually read results. It won't run anything until then. – Joel Coehoorn Oct 25 '12 at 18:16

1 Answers1

1

I think I found what your issue is - understanding the concept of IQueryable. Here is what it says in this article: Lazy Loading With The LazyList

IQueryable is the cornerstone of Linq To Sql, and has (what I think) is a killer feature: delayed execution. IQueryable essentially creates an Expression for you that you can treat as an enumerable list - and only when you iterate or ask for a value will the query be executed.

So you probably never used the result, and that's why it was never called. .NET framework only built the expression tree for you, but did not do any processing.

See also: IQueryable vs. IEnumerable.

Community
  • 1
  • 1
Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
  • Well, based on what you posted here got me thinking how to test that the result set was actually loading. So I through it in a for each loop. Low and behold, I think I found the true nature of the problem as I received a runtime error: Method 'Boolean Test(PbShipping.CUSTOMER)' has no supported translation to SQL That really stinks, but now I know that it was simply failing silently for some reason. Thanks for your help! I'm marking you as the answer since it's on track for the most part and helped me find the culprit! – David Peterson Oct 25 '12 at 18:25