Tuesday, December 27, 2011

LINQ To LDAP: Visiting the Locals

I recently ran into a problem with how LINQ to LDAP's expression visitor was working. This expression:
source.Where(u=> objectGuid.HasValue && u.objectGuid == objectGuid.Value)
was throwing a NullReferenceException. The problem was related to that first condition. The visit constant for QueryTranslator was making an assumption that for each constant it found there would be a corresponding member access.

My hackish solution was simply to ignore constants that don't have a corresponding property. Well that worked, but I saw two problems. First it created unnecessarily complex filters (& and | where one wasn't necessary). The second issue was the InvalidOperationException caused when .Value was called for a nullable without a value.

So fast forward several days of on and off coding (Christmas is for family and coding!) and I think I have a solution. I already borrowed the SubtreeEvaluator so I just needed to create a visitor that would rewrite only boolean constants. Well, I ended up creating two. One to rewrite and then another to remove redundant and unnecessary values. When I finish refactoring, you'll be able to find the BooleanRewriter and BooleanReducer in the Visitors folder.
//if objectGuid doesn't have a value the expression will reduce to:
source.Where(u=> false)

//if objectGuid has a value then the expression will reduce to:
source.Where(u=> u.objectGuid == objectGuid.Value)

3 comments:

  1. Was the NullReferenceException a result of objectGuid being NULL?

    I couldn't quite follow your statement:
    "making an assumption that for each constant it found there would be a corresponding member access"

    Thanks!

    ReplyDelete
    Replies
    1. No, it was a result of it trying to call _currentProperty.FormatValueToFilter. Since no member expression had actually been seen when it evaluated the constant, _currentProperty was null. I made a poor assumption that constants would be encountered on the other end of a binary expression (i.e. x.SomeProperty == constant).

      Delete
    2. Thanks! This makes sense to me now :)

      Delete