【问题标题】:How to make all fields search in ASP.Net Api如何在 ASP.Net Api 中搜索所有字段
【发布时间】:2021-05-31 03:20:24
【问题描述】:

我有这个 Get 方法:

[HttpGet]
public async Task<ActionResult<IEnumerable<Customer>>> GetCustomers(string s, int page, int page_size)
{
    IQueryable<Customer> query = _context.Customers;
    if (!string.IsNullOrEmpty(s))
    {
        var stringProperties = typeof(Customer).GetProperties();
        query = query.Where(c => stringProperties.Any(prop => prop.GetValue(c, null).ToString().Contains(s)));
    }
    return await query.Skip((page - 1) * page_size).Take(page_size).ToListAsync();
}

但是我的搜索实现不起作用,我得到了这个错误

.Where(m =&gt; __stringProperties_0 .Any(prop =&gt; prop.GetValue(obj: m, index: null).ToString().Contains(__8__locals1_s_1))) 不能 翻译

我该如何解决这个问题?

【问题讨论】:

  • 您可以在 DbContext where 中使用反射。当它执行时,它将转换为 SQL 查询,这在您的情况下是不可能的。
  • 我还想补充一点,你必须先创建表达式树。以下链接与您尝试实现的相似。stackoverflow.com/questions/58320767/…

标签: c# asp.net asp.net-mvc linq asp.net-core


【解决方案1】:

嗯,你正在处理的基本错误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);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多