如何在LINQ表达式树中实现.Any()方法以构建DbSet筛选逻辑
C# 表达式树构建Any方法调用异常修复方案
错误原因
No generic method 'Any' on type 'System.Linq.Queryable' is compatible异常核心原因是:实体导航属性Parties的类型为实现IEnumerable<M2M_Transactions_Party>的集合(常见为ICollection<M2M_Transactions_Party>),不属于IQueryable<T>类型,无法匹配Queryable.Any的方法签名,需要改为调用Enumerable.Any方法。
修正方案
只需要将Expression.Call调用的方法所属类从typeof(Queryable)改为typeof(Enumerable)即可,修改后的对应代码段如下:
// 将原来的typeof(Queryable)替换为typeof(Enumerable)即可 var anyCall = Expression.Call( typeof(Enumerable), "Any", new[] { tM2M }, expM2M, internalLambda );
完整修正后代码
private IQueryable<dbo.Transaction> _FilterTransactionPartyType(ParameterExpression param, IQueryable<Transaction> query, string transactionPartyType) { MemberExpression expM2M = Expression.PropertyOrField(param, "Parties"); Type tM2M = typeof(M2M_Transactions_Party); ParameterExpression paramM2m = Expression.Parameter(tM2M, "m2m"); // 构建Any内部的筛选逻辑:m2m => m2m.Party.Name 匹配规则 && m2m.PartyType.Name == transactionPartyType System.Reflection.PropertyInfo piParty = tM2M.GetProperty("Party"); System.Reflection.PropertyInfo piPartyName = piParty.PropertyType.GetProperty("Name"); System.Reflection.PropertyInfo piPartyType = tM2M.GetProperty("TransactionPartyType"); System.Reflection.PropertyInfo piPartyTypeName = piPartyType.PropertyType.GetProperty("Name"); MemberExpression expPartyType = Expression.Property(paramM2m, piPartyType); MemberExpression expPartyTypeName = Expression.Property(expPartyType, piPartyTypeName); ConstantExpression expPartyTypeValue = Expression.Constant(transactionPartyType, typeof(string)); BinaryExpression isPartyTransactionType = Expression.Equal(expPartyTypeName, expPartyTypeValue); MemberExpression expParties = Expression.Property(paramM2m, piParty); MemberExpression expParty = Expression.Property(expParties, piPartyName); BinaryExpression isParty = _Filter(expParty); BinaryExpression isPartyAndType = Expression.AndAlso(isParty, isPartyTransactionType); Expression<Func<M2M_Transactions_Party, bool>> internalLambda = Expression.Lambda<Func<M2M_Transactions_Party, bool>>(isPartyAndType, paramM2m); // 核心修改:将Queryable改为Enumerable,匹配导航属性的集合类型 var anyCall = Expression.Call( typeof(Enumerable), "Any", new[] { tM2M }, expM2M, internalLambda ); var lambda = Expression.Lambda<Func<Transaction, bool>>(anyCall, param); return query.Where(lambda); }
扩展说明
如果遇到源是IQueryable<T>类型需要调用Queryable.Any的场景,需要先将集合转为IQueryable,对应代码如下:
// 先调用AsQueryable将集合转为IQueryable类型 var asQueryableCall = Expression.Call( typeof(Queryable), "AsQueryable", new[] { tM2M }, expM2M ); // 再调用Queryable.Any var anyCall = Expression.Call( typeof(Queryable), "Any", new[] { tM2M }, asQueryableCall, internalLambda );
内容的提问来源于stack exchange,提问作者Mandelbrotter
相关产品推荐
相关产品推荐

