views:

48

answers:

1

How do I build Linq Expressions for aggregate classes? Let me explain with an example of what I am trying to do. Say, I want to find all employees with pay not equal to 50000 and here's the class structure.

    Employee e1 = new Employee { Name = "Jane", PDetail = new PayDetail { Salary = 100000 } };
    Employee e2 = new Employee { Name = "Joe", PDetail = new PayDetail { Salary = 50000 } };

    emps.Add(e1);
    emps.Add(e2);

//I started doing it this way and this code DOES NOT compile

var parameter = Expression.Parameter(typeof(PayDetail));

var where = Expression.NotEqual(Expression.Property(parameter, "Salary"), Expression.Constant(50000));

var pred = Expression.Lambda(where, parameter);

var query = Enumerable.Where(emps, (Func<PayDetail, Boolean>)pred.Compile());

EDIT: Any help with the null issue (as noted in the comments)? Thanks

A: 

You're not passing the correct arguments to the Enumerable.Where method. You are passing a list of Employee and a method that works on PayDetail. You could use

var query = Enumerable
    .Where(emps.Select(e => e.PDetail), (Func<PayDetail, Boolean>)pred.Compile());

or the shorter version

var query = emps.Select(e => e.PDetail)
    .Where((Func<PayDetail, Boolean>)pred.Compile());

Which will get you the right PayDetails but not the right Employees'. I believe you're really looking for:

var parameter = Expression.Parameter(typeof(Employee));

var where = Expression.NotEqual(Expression.Property(
    Expression.Property(parameter, "PDetail"), "Salary"), 
        Expression.Constant(50000));

var pred = Expression.Lambda(where, parameter);

var query = emps.Where((Func<Employee, Boolean>)pred.Compile());
Yuriy Faktorovich
But then how do I get the employee details as well for a condition like "Employees with the name of Jane and salary of 100000"?
DotnetDude
@DotnetDude check out my changes.
Yuriy Faktorovich
Wow, that works! I looked around a lot online before I posted this. Can you point me to an online Linq resource that goes in depth on Expression trees and advanced stuff? I am not exactly sure how you got this working. Thanks
DotnetDude
Also, what if I had a List<PayDetail> instead of a PDetail as a part of Employee?
DotnetDude
@DotnetDude actually I just played around with what you had already done. Sometimes it helps just getting another eye on the problem. Doing the List<PayDetail> looks hard, will work on it later when I have time. It looks like you'd need to grab the Exression of the `Enumerable.Any`.
Yuriy Faktorovich
@Yuriy - The code throws a null exception if one of the employee does not have the PDetail or if the PDetail = null in the initialization.
DotnetDude