3

I'm attempting to filter results from a database using Entity Framework CTP5. Here is my current method.

IQueryable<Form> Forms = DataContext.CreateFormContext().Forms;
foreach(string header in Headers) {
    Forms = Forms.Where(f => f.GetType()
                              .GetProperty(header)
                              .GetValue(f, null)
                              .ToString()
                              .IndexOf(filter,
                                  StringComparison.InvariantCultureIgnoreCase) >= 0);
}

However, I found that GetValue doesn't work using Entity Framework. It does when the type if IEnumerable<> but not IQueryable<>

Is there an alternative I can use to produce the same effect?

Gabe
  • 84,912
  • 12
  • 139
  • 238
MyNameIsJob
  • 2,508
  • 2
  • 17
  • 17
  • 1
    difference between IEnumerable and IQueryable is that Linq for Objects (IEnumerable) takes delegates as parameters and executes code directly so anything that compiles is possible. EF uses IQueryable and its expression parser has limits to what it is able to recognize and parse. – Pauli Østerø Jan 08 '11 at 07:23

1 Answers1

5
public static IQueryable<T> Like<T>(this IQueryable<T> source, string propertyName, string keyword) {
    Type type = typeof(T);
    ParameterExpression parameter = Expression.Parameter(type, "param");
    MemberExpression memberAccess = Expression.MakeMemberAccess(parameter, type.GetProperty(propertyName));

    ConstantExpression constant = Expression.Constant("%" + keyword + "%");
    MethodInfo contains = memberAccess.Type.GetMethod("Contains");

    MethodCallExpression methodExp = Expression.Call(memberAccess, contains, Expression.Constant(keyword));
    Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(methodExp, parameter);
    return source.Where(lambda);
}

You would call it like so

Forms = Forms.Like(header, filter);

I haven't done any validation of the passed parameters. For instance you have to validate that the Contains method exists on the type of the property you're validating against. So it won't work on an int or anything like that.

Buildstarted
  • 26,529
  • 10
  • 84
  • 95