Parameterized Query from an Expression Tree in Entity Framework Core

.net-core c# entity-framework-core linq-to-sql

Accepted Answer

According to the link you gave, EF utilizes a SQL parameter for variable values, therefore rather than developing anExpression.Constant You will get a parameterized query if you construct a variable reference for the value provided in (which in C# is always a field reference). The easiest option seems to be to reference a class object created to retain the value, mimicking how the compiler handles a lambda outer scope variable reference.

Unlike Expression.Constant obtaining the precise kind of the object is difficult.object argument, making it a generic type instead:

public static class IQueryableExt {
    private sealed class holdPropertyValue<T> {
        public T v;
    }

    public static IQueryable<T> WhereEquals<T, TValue>(this IQueryable<T> query, string propertyName, TValue propertyValue) {
        // p
        var pe = Expression.Parameter(typeof(T));

        var property = Expression.PropertyOrField(pe, propertyName);
        var holdpv = new holdPropertyValue<TValue> { v = propertyValue };
        //var value = Expression.Constant(propertyValue);
        var value = Expression.PropertyOrField(Expression.Constant(holdpv), "v");

        var predicateBody = Expression.Equal(
            property,
            value
        );
        var wf = Expression.Lambda<Func<T, bool>>(predicateBody, new ParameterExpression[] { pe });


        //var v = (int)propertyValue;
        //Expression<Func<Accounts,bool>> wf = (Accounts a) => a.Actid == v;

        wf.Dump();

        var whereCallExpression = Expression.Call(
            typeof(Queryable),
            "Where",
            new[] { typeof(T) },
            query.Expression,
            wf
        );

        return query.Provider.CreateQuery<T>(whereCallExpression);
    }
}

If you must succeed in anobject Instead of creating the suitable type of object dynamically, it is easier to include a conversion to the appropriate type (which won't impact the output SQL).holdPropertyValue and give it a value such that:

public static IQueryable<T> WhereEquals2<T>(this IQueryable<T> query, string propertyName, object propertyValue) {
    // p
    var pe = Expression.Parameter(typeof(T), "p");
    // p.propertyName
    var property = Expression.PropertyOrField(pe, propertyName);

    var holdpv = new holdPropertyValue<object> { v = propertyValue };
    // Convert.ChangeType(holdpv.v, property.Type)
    var value = Expression.Convert(Expression.PropertyOrField(Expression.Constant(holdpv), "v"), property.Type);

    // p.propertyName == Convert.ChangeType(holdpv.v, property.Type)
    var predicateBody = Expression.Equal(
        property,
        value
    );
    // p => p.propertyName == Convert.ChangeType(holdpv.v, property.Type)
    var wf = Expression.Lambda<Func<T, bool>>(predicateBody, new ParameterExpression[] { pe });

    // Queryable.Where(p => p.propertyName == Convert.ChangeType(holdpv.v, property.Type))
    var whereCallExpression = Expression.Call(
        typeof(Queryable),
        "Where",
        new[] { typeof(T) },
        query.Expression,
        wf
    );

    // query.Where(p => p.propertyName == Convert.ChangeType(holdpv.v, property.Type))
    return query.Provider.CreateQuery<T>(whereCallExpression);
}
0
3/3/2020 11:01:47 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow