使EF core“点赞”功能动态表达

Arm*_*and 8 c# .net-core asp.net-core-webapi asp.net-core-2.0 ef-core-2.0

我编写了一些代码来制作动态表达式来过滤我的分页。我正在尝试制作 EF Core 内置函数的动态表达式以进行搜索 ( EF.Functions.Like)。

我尝试过像bottom这样的方法,但它是一个扩展方法,调用该方法时不使用第一个参数。我不知道如何遵循==> Ef => Function => Like的方式。
该方法应该像这样使用=>Ef.Functions.Like("Property to search", "%Some Pattern")

var likeMethod = typeof(DbFunctionsExtensions)
                        .GetMethods()
                        .Where(p => p.Name == "Like")
                        .First();
string pattern = $"%{finalConstant}%"; 

ConstantExpression likeConstant = Expression.Constant(pattern,typeof(string));

// the member expression is the property expression for example p.Name
var likeMethodCall = Expression.Call(method: likeMethod, arguments: new[] { memberExpression, likeConstant });

var searchLambda = Expression.Lambda<Func<T, bool>>(likeMethodCall, parameter);
query = query.Where(searchLambda);
Run Code Online (Sandbox Code Playgroud)

但它抛出异常说

为调用方法“Boolean Like(Microsoft.EntityFrameworkCore.DbFunctions, System.String, System.String)”提供的参数数量不正确\r\n参数名称: 方法

Але*_*ров 6

我根据这篇文章实现了动态搜索\n .NET Core Npgsql.EntityFrameworkCore ILikeExpression \n这就是我所做的:

\n

我实现了 [Searchable] 属性,用它来标记将执行搜索的属性。属性仅是 string 类型,如果有必要我可以解释如何搜索 long 和 int 类型的属性。

\n
[AttributeUsage(AttributeTargets.Property)]\npublic class SearchableAttribute : Attribute\n{\n}\n
Run Code Online (Sandbox Code Playgroud)\n

为 IQueryable 创建了一个扩展,它从搜索中获取输入字符串,并根据指定的属性实现 Like 函数

\n
public static class QueryableExtension\n{\n    public static IQueryable<TEntityDto> ExecuteQueryFilter<TEntityDto>(this IQueryable<TEntityDto> queryable, string query)\n        where TEntityDto : class, IEntityDto\n    {\n        // If the incoming request is empty, skip the search\n        if (string.IsNullOrEmpty(query))\n        {\n            return queryable;\n        }\n\n        // We get all properties with type of string marked with our attribute\n        var properties = typeof(TEntityDto).GetProperties()\n            .Where(p => p.PropertyType == typeof(string) &&\n                        p.GetCustomAttributes(typeof(SearchableAttribute), true).FirstOrDefault() != null)\n            .Select(x => x.Name).ToList();\n\n        // If there are no such properties, skip the search\n        if (!properties.Any())\n        {\n            return queryable;\n        }\n\n        // Get our generic object\n        ParameterExpression entity = Expression.Parameter(typeof(TEntityDto), "entity");\n\n        // Get the Like Method from EF.Functions\n        var efLikeMethod = typeof(DbFunctionsExtensions).GetMethod("Like",\n            BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,\n            null,\n            new[] { typeof(DbFunctions), typeof(string), typeof(string) },\n            null);\n\n        // We make a pattern for the search\n        var pattern = Expression.Constant($"%{query}%", typeof(string));\n\n        // Here we will collect a single search request for all properties\n        Expression body = Expression.Constant(false);\n\n        foreach (var propertyName in properties)\n        {\n            // Get property from our object\n            var property = Expression.Property(entity, propertyName);\n\n            // \xd0\xa1all the method with all the required arguments\n            Expression expr = Expression.Call(efLikeMethod,\n                    Expression.Property(null, typeof(EF), nameof(EF.Functions)), property, pattern);\n\n            // Add to the main request\n            body = Expression.OrElse(body, expr);\n        }\n\n        // Compose and pass the expression to Where\n        var expression = Expression.Lambda<Func<TEntityDto, bool>>(body, entity);\n        return queryable.Where(expression);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Dto 对象本身如下所示:

\n
public class CategoryDto : IEntityDto\n{\n    public long Id { get; set; }\n\n    [Searchable]\n    public string Name { get; set; }\n\n    [Searchable]\n    public string IconKey { get; set; }\n\n    public long UploadId { get; private set; }\n\n    [Searchable]\n    public string UploadFileName { get; set; }\n\n    [Searchable]\n    public string CreatedBy { get; set; }\n    public DateTime Created { get; set; }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我在 100 万条记录上测试了这种搜索方法,其中对象名称为一到五个单词。搜索过程非常快。这里的性能优势是表达式在数据库端转换为 LINQ to SQL

\n


Ric*_*ema 0

正如评论中提到的,您需要包含EF.Functions作为第一个参数:

var likeMethodCall = Expression.Call(likeMethod, new []
{
    Expression.Property(null, typeof(EF).GetProperty("Functions")),
    memberExpression,
    likeConstant 
});
Run Code Online (Sandbox Code Playgroud)