Sunday, September 08, 2013

Dynamic Linq Expressions; Conditionally Checking Nullable Type Example

While searching for an example of this, I came up short.  Most of the examples of building Linq expressions I ran across were very complicated and confusing.
This simple example builds an expression that compares 2 DateTime values, one of which is a nullable date.  In the process it demonstrates conditionally accessing different property values.

class Peep
{
    public string FirstName { get; set; }
    public DateTime? DOB { get; set; }
}

class Program
{

    static void Main( string[] args )
    {
        var peeps = new List<Peep>
        {
            new Peep { FirstName = "brad", DOB = DateTime.Now.AddDays( -1 ) },
            new Peep { FirstName = "fred", DOB = DateTime.Today },
            new Peep { FirstName = "Mr. null date" } };
        
        var constantComparisonExpression = Expression.Constant( DateTime.Today );

        var BirthDateParameter = Expression.Parameter( typeof( Peep ), "DOB" );
        var birthDateProperty = Expression.Property( BirthDateParameter, "DOB" );
        var hasValue = MemberExpression.Property( birthDateProperty, "HasValue" );
        var actualValue = MemberExpression.Property( birthDateProperty, "Value" );
        var bogusValue = Expression.Constant( DateTime.MinValue );
        var condition = Expression.Condition( hasValue, actualValue, bogusValue );

        var isEqual = Expression.Equal( condition, constantComparisonExpression );
        var finalExpr = Expression.Lambda<Func<Peep, bool>>( isEqual, BirthDateParameter );

        // Equivalent of .Where( peep => (peep.DOB.HasValue ? peep.DOB.Value : DateTime.MinValue) == DateTime.Today )
        var wrist = peeps.AsQueryable().Where( finalExpr ).ToList();
        if ( wrist.Count == 1 )
        {
            /// Should find fred
            Console.WriteLine( wrist[0].FirstName );
        }
        else
        {
            Console.WriteLine( "no match" );
        }
        Console.ReadLine();
    }

}

If you need to combine multiple expressions, see this.  Don't bother searching further, that works.