Entity Framework Plus Core Filter中WhereDynamic调用自定义扩展方法报错求助
动态查询中自定义扩展方法无法识别的问题解决
模型定义
public class Data { public int ID { get; set; } public string? Name { get; set; } public virtual ICollection<Property>? Properties { get; set; } } public partial class Property { public int? ID { get; set; } public string? Name { get; set; } public string? Value { get; set; } public int? ParentID { get; set; } public virtual Data? Parent { get; set; } }
基础动态查询可正常运行
使用简单条件的动态查询无异常:
var condition = "x.Properties != null && x.Properties.Any( y => y.Name == \"Date\" && y.Value == \"12/11/2022\" )"; var result = context.Data.Include( x => x.Properties ).WhereDynamic( x => condition );
复杂动态查询抛出异常
当条件中引入自定义扩展方法ToDateTime(103)时,执行查询会报错:
var condition = "x.Properties != null && x.Properties.Any( y => y.Name == \"Date\" && y.Value != null && y.Value.ToDateTime(103) < DateTime.Parse(\"12/11/2022\") )";
报错信息
Oops! No applicable member has been found for the expression. The error occurred for expression "." at position 3 near ".Where(x => x.Properties".
普通Where方法可正常执行
相同逻辑用原生LINQ的Where方法完全正常:
var result = context.Data.Include( x => x.Properties ).Where( x => x.Properties != null && x.Properties.Any( y => y.Name == "Date" && y.Value != null && y.Value.ToDateTime(103) < DateTime.Parse("12/11/2022") ) );
问题原因
动态查询库(如Dynamic LINQ)解析字符串条件时,默认仅识别.NET内置方法与类型,无法自动识别自定义扩展方法。而原生Where是编译时解析,编译器能自动绑定扩展方法,因此无报错。
解决方法
方法1:注册自定义扩展方法到动态查询解析器
以常用的System.Linq.Dynamic.Core库为例,需提前将自定义扩展方法注册到解析器:
- 确保扩展方法是静态类中的静态方法:
public static class StringExtensions { public static DateTime ToDateTime(this string input, int format) { // 自定义转换逻辑示例 return DateTime.ParseExact(input, "dd/MM/yyyy", CultureInfo.InvariantCulture); } }
- 在查询前注册该方法:
// 获取ToDateTime方法的MethodInfo var toDateTimeMethod = typeof(StringExtensions).GetMethod( nameof(StringExtensions.ToDateTime), new[] { typeof(string), typeof(int) } ); // 注册到Dynamic LINQ解析器 DynamicLinqParser.Default.ParseMethods.Add(toDateTimeMethod);
- 若注册后仍无法识别,将动态查询字符串中的扩展方法调用改为静态方法格式:
var condition = "x.Properties != null && x.Properties.Any( y => y.Name == \"Date\" && y.Value != null && StringExtensions.ToDateTime(y.Value, 103) < DateTime.Parse(\"12/11/2022\") )";
方法2:改用表达式树构建动态条件
跳过字符串解析,直接用表达式树手动构建查询条件,复用原生Where的逻辑:
// 构建表达式参数 var xParam = Expression.Parameter(typeof(Data), "x"); var yParam = Expression.Parameter(typeof(Property), "y"); // 构建y的子条件 var nameEquals = Expression.Equal( Expression.Property(yParam, nameof(Property.Name)), Expression.Constant("Date") ); var valueNotNull = Expression.NotEqual( Expression.Property(yParam, nameof(Property.Value)), Expression.Constant(null, typeof(string)) ); var toDateTimeCall = Expression.Call( typeof(StringExtensions), nameof(StringExtensions.ToDateTime), null, Expression.Property(yParam, nameof(Property.Value)), Expression.Constant(103) ); var dateCompare = Expression.LessThan( toDateTimeCall, Expression.Constant(DateTime.Parse("12/11/2022")) ); var yCondition = Expression.AndAlso(Expression.AndAlso(nameEquals, valueNotNull), dateCompare); // 构建Any方法调用 var anyCall = Expression.Call( typeof(Enumerable), nameof(Enumerable.Any), new[] { typeof(Property) }, Expression.Property(xParam, nameof(Data.Properties)), Expression.Lambda(yCondition, yParam) ); // 构建x.Properties != null的条件 var propertiesNotNull = Expression.NotEqual( Expression.Property(xParam, nameof(Data.Properties)), Expression.Constant(null, typeof(ICollection<Property>)) ); // 合并总条件并执行查询 var totalCondition = Expression.AndAlso(propertiesNotNull, anyCall); var whereLambda = Expression.Lambda<Func<Data, bool>>(totalCondition, xParam); var result = context.Data.Include(x => x.Properties).Where(whereLambda);
方法3:提前转换数据或改用内置函数
若业务允许,可将Property.Value中的日期字符串提前转为DateTime类型存入数据库(新增字段),或使用动态查询支持的内置日期转换函数,避免依赖自定义扩展方法。
内容的提问来源于stack exchange,提问作者ghennady dovgani
相关产品推荐
相关产品推荐

