dimanche 26 juillet 2015

C# - Dynamically create lambda search on IQueryable on nested objects

I'm trying to build a dynamic search on nested objects, which will later be sent to EF and SQL Server. So far, I'm able to search on all properties of the first object. Here's a very simplified version:

public class User
{
    public string Name { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    public string City { get; set; }
}

public class MyClass<TEntity> where TEntity : class {
    public IQueryable<TEntity> applySearch(IQueryable<TEntity> originalList, string propName, string valueToSearch) {

        ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity), "p");
        PropertyInfo propertyInfo = typeof(TEntity).GetProperty(propName);
        MemberExpression member = Expression.MakeMemberAccess(parameterExpression, propertyInfo);
        lambda = Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(member, Expression.Constant(valueToSearch)), parameterExpression);

        return originalList.Where(expression);
    }
}

When propName = "Name" everything is fine, but when propName = "Address.City", the propertyInfo is null, and I get this error on the member assignment line:

System.ArgumentNullException: Value cannot be null

I was able to obtain the propertyInfo of the nested property using the solution from this answer:

PropertyInfo propertyInfo = GetPropertyRecursive(typeof(TEntity), propName);
...

private PropertyInfo GetPropertyRecursive(Type baseType, string propertyName)
{
    string[] parts = propertyName.Split('.');

    return (parts.Length > 1)
        ? GetPropertyRecursive(baseType.GetProperty(parts[0]).PropertyType, parts.Skip(1).Aggregate((a, i) => a + "." + i))
        : baseType.GetProperty(propertyName);
}

But then I get this error on member assignment:

System.ArgumentException: Property 'System.String City' is not defined for type 'User'

I don't know if I'm on right track here. How can I make a dynamic search on nested objects, so that this can be turned into a lambda and later sent to SQL?





Aucun commentaire:

Enregistrer un commentaire