views:

239

answers:

1

I am trying to create Linq Expression that I can use to query child entity for parent properties(PATIENT entity in this case), using this method:

private IQueryable<LAB_ORDER> SelectFilter(string fieldName, string value)
{
   var param = Expression.Parameter(typeof(PATIENT), "item");
   var field = Expression.PropertyOrField(param, fieldName);

   var search = Expression.Constant(value, typeof(string));

   var body = Expression.Call(field, "Contains", null, search);

   Expression<Func<LAB_ORDER, bool>> lambda;

   if (String.IsNullOrEmpty(value))
   {
      lambda = x => true;
   }
   else
   {
      lambda = Expression.Lambda<Func<LAB_ORDER, bool>>(body, parm);

   }

   var linqFilter = from e in context.LAB_ORDERS select e;

   return linqFilter.Where(lambda);
} 

Looks like it builds an expression correctly, but exception I am getting is this:

System.ArgumentException: ParameterExpression of type 'PATIENT' cannot be used for delegate parameter of type LAB_ORDER'.

While I can do linqFilter.Where( x => x.PATIENT.LAST_NAME == "Smith") without any problems, can't use expression above, which should translate to something similar to this. How would I fix the expression above to correct it? I am eagerly loading parent entity with a child so that's not a problem.

EDIT

From Anders reply it looks like I need to modify lambda expression to:

lambda = Expression.Lambda<Func<PATIENT, bool>>(body, parm);

Now when I try to use it, linqFilter.Where(lambda) gives me compile error "No suitable overload" which I understand why - linqFilter is "IQueryable<LAB_ORDER>", not "IQueryable<PATIENT>", so how should I do that? Just to sum things up, the only question remains - how to create Expression for parent properties?

+2  A: 

In the following statement you say that you will build a function which takes a LAB_ORDER argument and returns a bool.

lambda = Expression.Lambda<Func<LAB_ORDER, bool>>(body, parm);

However the parm variable contains a PATIENT. You will have to rewrite the expression lambda to take an LAB_ORDER instead. If I understand your intentions you correctly the expression you are trying to express is

x => x.PATIENT.[fieldnName].Contains()

but the expression you've built is

x => x.[fieldName].Contains()
Anders Abel
Thanks for reply Anders. That is exactly right - I am trying to express x => x.PATIENT.[fieldName].Contains(). But if I try var param = Expression.Parameter(typeof(LAB_ORDER), "item"); then I get an exception on a next line: var field = Expression.PropertyOrField(param, "PATIENT.LAST_NAME"); - "PATIENT.LAST_NAME is not a member of LAB_ORDER. Can you show how I need to modify lambda expression? Thanks
Victor
Also, if I change my lambda to lambda = Expression.Lambda<Func<PATIENT, bool>>(body, parm); thenlinqFilter.Where(lambda) gives me compile error - no suitable overload.
Victor
You can't use Expression.PropertyOrField(param, "PATIENT.LAST_NAME"); You have to build a nested expression that first picks out the pation from the LAB_ORDER and then the LAST_NAME from the patient.
Anders Abel
Thanks, could you show how to do that? Haven't done nested expressions so far.
Victor
Is it something like this: Expression.PropertyOrField(Expression.PropertyOrField(param, "PATIENT"), "LAST_NAME"); or more complicated?
Victor
It looks correct to me, but I have not worked with Expression trees this way either, so I don't know the details - you will have to do some tests.
Anders Abel
Something new every day:-) I'll give it a try shortly let you know if you curious
Victor
Yes, that was it, thanks for advice
Victor