2009/08/17

With FAIL

If you've had the pleasure of working in VB.Net (kill self). If your lazy like me. You've probably used a WITH statement to shorthand calls to properties and methods.

For those who haven't, a WITH statement can be implemented as below:


With myObject = New SomeObject()
.Property1 = "foo"
.Property2 = "bar"
.Execute()
End With


Simple enough, right. Now enter Linq...

Linq queries (Linq2SQL, Linq2nHibernate, Linq2XML) add a great deal of functions to items derived from IEnumereable (Querayable objects, Lists, etc). The main method I was using on my project was the .Where() extension method.

I'll just mention that I prefer the Extension method/Lambda syntax in C# over that of vb. Primarily because I am lazy and "=>" is two keystrokes versus "Function(x)". Now here is where my laziness caught up with me.

I was implementing a simple search function that would take in a search criteria class. The class had a few properties and a list. The properties mapped to various fields on a customer class the list maps to a view that I've associated as a child class to the customer class in my dbml. All criteria are optional on the search to allow for insanely as hoc querying.

So as I enter the .Search(criteria As SearchCriteria) method I tossed in a With statement (due to the laziness). Basically as follows:


Public Function Search(criteria As SearchCriteria) As List(Of Customer)
With criteria
Dim results = Repository(Of Customer).GetTable()
If Not(String.IsNullOrEmpty(.Name)) Then
results = results.Where(Function(r) r.Name.Contains(.Name))
End If

If (.CustomerId IsNot Nothing) Then
results = results.Where(Function(r) r.Id = .CustomerId)
End If

...Continue a dozen more times ...

End With
Return results
End Sub



So I step through debugging on this method and I see that the .Where's are filtering down the results as I'd expect. However when I leave the sub, a NullReferenceException is thrown from the internals of Linq2SQL... FAIL.

Thinking I may have screwed up something with the .Where's, even though a watch shows that it's good, I switch up how I do the where to
results = From r In results Where r.Id = .CustomerId
I step through, expand the watch, and it looks good. Continue running to end of method... FAIL. Again a NRE from the internals of Linq2SQL.

After cursing at length, dumping all the objects out of my dbml and re-creating. Still FAIL. Then it dawns on me. Linq2SQL queries, like all Linq queries don't execute when most people would expect. This is a good thing. You can append numerous Where statements, Orders, etc and the you don't have a call to the database until you actually go to retrieve a value (a ToList() or ToArray() will cause this as will binding the list to a webform object). Of course when I expand the watch on results it executed the underlying queries. So where did the phantom NRE come from?

Apparently, using a With statement does some kind of voodoo with memory addressing. So my .CustomerId is not the same as criteria.CustomerID. When the results were returned, we were outside the With so the framework had no idea where these .Whatevers were coming from. *sigh* So much for being lazy.

I remove the With statement and everything just works... Kill Self. That is about a day of writing, cursing, rewriting, cursing, smoking, re-rewriting, cursing that I won't get back. So that is my tale of shame, I am not proud.

Comments