嗯,你正在处理的基本错误PropertyInfo.GetValue。在 SQL 服务器端,您没有对象,也无法以这种方式获取值。你可以做的是指示 EF 如何比较属性。
我创建了通用函数,它可能有助于创建此类查询。它不仅可以处理字符串,还可以用于任何类型。
如果可能的话,还要考虑使用扩展。
public static IQueryable<Customer> FilterCustomers(this IQueryable<Customer> query, string s)
{
if (!string.IsNullOrEmpty(s))
{
query = query.FilterByProperties(s, (prop, value) => prop.Contains(value), true)
}
return query;
}
public static Task<List<T>> PaginateAsync<T>(this IQueryable<T> query, int page, int page_size)
{
return query.Skip((page - 1) * page_size).Take(page_size).ToListAsync();
}
[HttpGet]
public Task<List<Customer>> GetCustomers(string s, int page, int page_size)
{
var query = _context.Customers.FilterCustomers(s);
return query.PaginateAsync(page, page_size);
}
及实施:
public static class QueryableExtensions
{
public static Expression<Func<T, bool>> MakePropertiesPredicate<T, TValue>(Expression<Func<TValue, TValue, bool>> pattern, TValue searchValue, bool isOr)
{
var parameter = Expression.Parameter(typeof(T), "e");
var searchExpr = Expression.Constant(searchValue);
var predicateBody = typeof(T).GetProperties()
.Where(p => p.PropertyType == typeof(TValue))
.Select(p =>
ExpressionReplacer.GetBody(pattern, Expression.MakeMemberAccess(
parameter, p), searchExpr))
.Aggregate(isOr ? Expression.OrElse : Expression.AndAlso);
return Expression.Lambda<Func<T, bool>>(predicateBody, parameter);
}
public static IQueryable<T> FilterByProperties<T, TValue>(this IQueryable<T> query, TValue searchValue,
Expression<Func<TValue, TValue, bool>> pattern, bool isOr)
{
return query.Where(MakePropertiesPredicate<T, TValue>(pattern, searchValue, isOr));
}
class ExpressionReplacer : ExpressionVisitor
{
readonly IDictionary<Expression, Expression> _replaceMap;
public ExpressionReplacer(IDictionary<Expression, Expression> replaceMap)
{
_replaceMap = replaceMap ?? throw new ArgumentNullException(nameof(replaceMap));
}
public override Expression Visit(Expression node)
{
if (node != null && _replaceMap.TryGetValue(node, out var replacement))
return replacement;
return base.Visit(node);
}
public static Expression Replace(Expression expr, Expression toReplace, Expression toExpr)
{
return new ExpressionReplacer(new Dictionary<Expression, Expression> { { toReplace, toExpr } }).Visit(expr);
}
public static Expression Replace(Expression expr, IDictionary<Expression, Expression> replaceMap)
{
return new ExpressionReplacer(replaceMap).Visit(expr);
}
public static Expression GetBody(LambdaExpression lambda, params Expression[] toReplace)
{
if (lambda.Parameters.Count != toReplace.Length)
throw new InvalidOperationException();
return new ExpressionReplacer(Enumerable.Range(0, lambda.Parameters.Count)
.ToDictionary(i => (Expression)lambda.Parameters[i], i => toReplace[i])).Visit(lambda.Body);
}
}
}