我已经编写了一些代码来制作动态表达式以过滤分页。
我正在尝试动态表达EF Core内置函数以进行搜索(EF.Functions.Like
)。
我尝试了类似bottom的方法,但这是一种扩展方法,调用该方法时不使用first参数。我不知道该怎么做==> 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);
但是它抛出异常
为调用方法'Boolean Like(Microsoft.EntityFrameworkCore.DbFunctions,System.String, System.String)'\ r \ n参数名称:方法
答案 0 :(得分:1)
我根据本文实现了动态搜索 [.NET Core Npgsql.EntityFrameworkCore ILikeExpression] [1] [1]:https://stackoverflow.com/questions/52038380/net-core-npgsql-entityframeworkcore-ilikeexpression 那就是我所做的:
我实现了[Searchable]属性,通过该属性我将标记执行搜索的属性。属性仅是字符串类型的,如有必要,我可以解释一下如何搜索long和int类型的属性。
[AttributeUsage(AttributeTargets.Property)]
public class SearchableAttribute : Attribute
{
}
已为IQueryable创建了扩展名,该扩展名从搜索中获取输入字符串并根据指定的属性实现Like函数
public static class QueryableExtension
{
public static IQueryable<TEntityDto> ExecuteQueryFilter<TEntityDto>(this IQueryable<TEntityDto> queryable, string query)
where TEntityDto : class, IEntityDto
{
// If the incoming request is empty, skip the search
if (string.IsNullOrEmpty(query))
{
return queryable;
}
// We get all properties with type of string marked with our attribute
var properties = typeof(TEntityDto).GetProperties()
.Where(p => p.PropertyType == typeof(string) &&
p.GetCustomAttributes(typeof(SearchableAttribute), true).FirstOrDefault() != null)
.Select(x => x.Name).ToList();
// If there are no such properties, skip the search
if (!properties.Any())
{
return queryable;
}
// Get our generic object
ParameterExpression entity = Expression.Parameter(typeof(TEntityDto), "entity");
// Get the Like Method from EF.Functions
var efLikeMethod = typeof(DbFunctionsExtensions).GetMethod("Like",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] { typeof(DbFunctions), typeof(string), typeof(string) },
null);
// We make a pattern for the search
var pattern = Expression.Constant($"%{query}%", typeof(string));
// Here we will collect a single search request for all properties
Expression body = Expression.Constant(false);
foreach (var propertyName in properties)
{
// Get property from our object
var property = Expression.Property(entity, propertyName);
// Сall the method with all the required arguments
Expression expr = Expression.Call(efLikeMethod,
Expression.Property(null, typeof(EF), nameof(EF.Functions)), property, pattern);
// Add to the main request
body = Expression.OrElse(body, expr);
}
// Compose and pass the expression to Where
var expression = Expression.Lambda<Func<TEntityDto, bool>>(body, entity);
return queryable.Where(expression);
}
}
Dto对象本身看起来像这样:
public class CategoryDto : IEntityDto
{
public long Id { get; set; }
[Searchable]
public string Name { get; set; }
[Searchable]
public string IconKey { get; set; }
public long UploadId { get; private set; }
[Searchable]
public string UploadFileName { get; set; }
[Searchable]
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
}
我在一百万条记录中测试了这种搜索方法,对象名称用一到五个词表示。搜索过程非常快。这里的性能优势是Expression在数据库端将LINQ转换为SQL
答案 1 :(得分:0)
这是一个可行的例子
public static Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> prop, string keyword)
{
var concatMethod = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) });
return Expression.Lambda<Func<T, bool>>(
Expression.Call(
typeof(DbFunctionsExtensions),
nameof(DbFunctionsExtensions.Like),
null,
Expression.Constant(EF.Functions),
prop.Body,
Expression.Add(
Expression.Add(
Expression.Constant("%"),
Expression.Constant(keyword),
concatMethod),
Expression.Constant("%"),
concatMethod)),
prop.Parameters);
}
query = query.Where(Like<User>(u => u.UserName, "angel"));