Ссылка, которую вы указали, объясняет, что EF использует параметр SQL для значений переменных, поэтому вместо создания Expression.Constant
для переданного значения, если вы создаете ссылку на переменную (которая в C# всегда является полем ссылка), тогда вы получите параметризованный запрос. Кажется, самое простое решение - скопировать то, как компилятор обрабатывает ссылку на внешнюю переменную области видимости лямбды, то есть создает объект класса для хранения значения и ссылки на него.
В отличие от Expression.Constant
, это нелегко чтобы получить фактический тип параметра object
, изменив его на общий тип c:
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);
}
}
Если вам нужно вместо этого передать object
, проще добавить преобразование в правильный тип (который не повлияет на сгенерированный SQL), вместо динамического создания правильного типа holdPropertyValue
и присвоения ему значения, так:
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);
}