8

I want to give the user the choice of searching by different properties. For instance

[INPUT TEXT] | [SELECT OPTION {ID, NAME, PHONE}] | [SEARCH]

And I would later build my query like this:

repository.Where(lambda-expression)

Where lambda-expression is build from the selected option {ID, NAME, PHONE} (For example: x => x.NAME.Equals(INPUT TEXT))

Is there a way to build the lambda from the Property name perhaps using reflection?

Thanks

3 Answers 3

26

You don't build a lambda expression - you build an expression tree. It's not terribly hard, but it takes a little patience. In your sample you'd probably need:

ParameterExpression parameter = Expression.Parameter(typeof(Foo), "x");
Expression property = Expression.Property(parameter, propertyName);
Expression target = Expression.Constant(inputText);
Expression equalsMethod = Expression.Call(property, "Equals", null, target);
Expression<Func<Foo, bool>> lambda =
   Expression.Lambda<Func<Foo, bool>>(equalsMethod, parameter); 

That's assuming:

  • The repository element type is Foo
  • You want to use a property called propertyName
  • You want to compare for equality against inputText
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, it worked like a charm... I did get an error at first, and I had to change my type from IEnumerable to IQueryable, but I should have been using IQueryable to begin with.
@AJC: Can you make the method a generic method and have it as a type parameter? Or just take the type as a normal parameter. It's hard to know what to advise as you haven't provided much context.
yeah, Sorry I got a little lazy there for a second. I'll pass the Type as a parameter... Thanks...
I am having a small problem. At first, I was using "Contains" for the method, but now I require an "Equals" comparator and I am getting this error: More than one method 'Equals' on type 'System.String' is compatible with the supplied arguments.. Any thoughts? Thanks
@AJC: Yes, use an alternative overload of Expression.Call which takes a MethodInfo instead of a string to identify the method.
|
3

For that sort of thing, I use something like this (note: does a Where "Like") :

 public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> source, string propertyName, string value) 
    {

        Expression<Func<TEntity, bool>> whereExpression = x => x.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, null, x, null).ObjectToString().IndexOf(value, StringComparison.InvariantCultureIgnoreCase) >= 0;

        return source.Where(whereExpression);


    }

1 Comment

This query is useful but when I checked using sql profiler, it first queries all the records and then applies the expression on top of it. How can we get the results including the filter expression in only one (optimised) query?
2

I had to face the same sort of problem and the following method resolved my problem perfectly.

PropertyInfo propertyInfoObj = MyClassObject.GetType().GetProperty(PropertyName);
repository.Where(x => propertyInfoObj.GetValue(x) == SearchValue).Select(x => propertyInfoObj.GetValue(x)).FirstOrDefault();

1 Comment

Have you checked Sql profiler to see what queries are being emitted? I have a feeling you're going to find your entire table being loaded into memory before the reflection code runs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.