首页 > 解决方案 > C# AspNet.Core 请求查询 -> EF Core 谓词表达式

问题描述

通过将查询参数转换为 EF Core 谓词表达式,通过 HTTP 请求在 Azure 终结点访问中最大化客户端大小的 UX。

标签: c#asp.netentity-frameworkazure-sql-database

解决方案


using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;

namespace EMWS_Projects.Services
{
    public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> True<T>() { return f => true; }
        public static Expression<Func<T, bool>> False<T>() { return f => false; }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                             Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
        }
    }

    public static class QueryToExpressionConverter
    {
        public static Expression<Func<T, bool>> GetExpressionFromIQueryCollection<T>(IQueryCollection queryCollection)
        {
            Expression<Func<T, bool>> predicate = PredicateBuilder.True<T>();
            foreach (KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues> entry in queryCollection)
            {
                predicate = predicate.And(GetExpressionFromEntry<T>(entry));
            }
            return predicate;
        }

        private static Expression<Func<T, bool>> GetExpressionFromEntry<T>(KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues> entry)
        {
            PropertyInfo property = typeof(T).GetProperty(entry.Key.Trim(), BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
            if (property == null) throw new Exception("Could not derive property from query parameter dictionary key.");
            TypeConverter converter = TypeDescriptor.GetConverter(property.PropertyType);
            List<string> values = entry.Value.ToList();
            if (values == null || values.Count == 0) throw new Exception("Could not parse query parameter's value using the given property.");
            Expression<Func<T, bool>> predicate = PredicateBuilder.False<T>();
            foreach(string value in values)
            {
                predicate = predicate.Or((T subject) => typeof(T).GetProperty(entry.Key).GetValue(subject).ToString() == value);
            }
            return predicate;
        }
    }
}

推荐阅读