Linq expression for condition when condition on child

Hello,

how can i build the following statement through linq expressions for translate to sql?

builder.Where(e => e.SomeChild.Name.ToLower() == "something");

builderis a DbContext. When I call it directly, it is correctly interpreted as

select ... from someTable 
inner join childTable on ... 
where LOWER(childTable.Name) = @someParam

so I create a where clause as follows:

private readonly Expression<Func<TEntity, TProperty>> _property;

private Expression<Func<TEntity, bool>> insensitiveEqualityPredicate(string formula)
        {
            var parameter = Expression.Parameter(typeof(TEntity));
            var property = (PropertyInfo)((MemberExpression)_property.Body).Member;
            var propertyParameter = Expression.Parameter(property.DeclaringType);
            var lowerExpression = Expression.Call(
                    Expression.Invoke(_property, propertyParameter),
                    typeof(string).GetMethods().Where(m => m.Name == "ToLower" && m.GetParameters().ToList().Count == 0).FirstOrDefault()
                    );
            return Expression.Lambda<Func<TEntity, bool>>(
                Expression.Equal(
                    lowerExpression,
                    Expression.Constant(formula.ToLower(), typeof(string))
                ),
                parameter
            );
        }

It works like a charm:

_property = e => e.Name;
...
builder.Where(insensitiveEqualityPredicate("whatever"));

But does not work for conditions for children:

_property = e => e.SomeChild.Name;
...
builder.Where(insensitiveEqualityPredicate("whatever"));

Because:

The LINQ expression 'Param_0.Name.Equal("whatever")' could not be translated and will be evaluated locally.

What is the right approach?

Thanks in advance.

+4
source share
1 answer

In my opinion, you have a _propertytype field Expression<Func<TEntity, TProperty>>(in this particular case, it is actually Expression<Func<TEntity, string>>) that is initialized with a lambda type expression e => e.Name, e => e.SomeChild.Nameetc.

, _property Body :

private readonly Expression<Func<TEntity, TProperty>> _property;

private Expression<Func<TEntity, bool>> insensitiveEqualityPredicate(string formula)
{
    return Expression.Lambda<Func<TEntity, bool>>(
        Expression.Equal(
            Expression.Call(_property.Body, "ToLower", Type.EmptyTypes),
            Expression.Constant(formula.ToLower(), typeof(string))
        ),
        _property.Parameters
    );
}
+3

Source: https://habr.com/ru/post/1663448/


All Articles