动态数据库调用时抛出ArgumentException异常的技术求助
问题分析与解决方案
核心问题
你的代码存在几个关键错误,导致了类型转换异常:
- 错误使用
Enumerable.SingleOrDefault而非Queryable.SingleOrDefault,前者针对内存集合操作,后者才是EF Core用于数据库查询的扩展方法。 - 构建
SingleOrDefault泛型方法时,错误用表达式类型作为泛型参数,而非实体类型(resourceType)。 - 生成的谓词表达式类型不匹配:DbSet
需要 Expression<Func<resourceType, bool>>,但你生成的是Func<IGroupMember, bool>。 - 使用
Expression.Invoke可能导致EF Core无法将表达式转换为SQL。
修正后的代码
1. 动态构建实体匹配表达式
替换原BuildExpression方法,生成与实体类型匹配的表达式:
private Expression BuildDynamicExpression(Type resourceType, int id) { // 获取实体的Id属性(实现IGroupMember接口) var idProperty = resourceType.GetProperty(nameof(IGroupMember.Id))!; // 构建参数表达式:x(类型为resourceType) var paramExpr = Expression.Parameter(resourceType, "x"); // 构建x.Id的访问表达式 var idPropertyExpr = Expression.Property(paramExpr, idProperty); // 构建Id常量表达式 var idConstantExpr = Expression.Constant(id, typeof(int)); // 构建相等表达式:x.Id == id var equalExpr = Expression.Equal(idPropertyExpr, idConstantExpr); // 生成Lambda表达式:x => x.Id == id return Expression.Lambda(equalExpr, paramExpr); }
2. 修正数据库查询逻辑
response = group.MapEntity<GroupDataResponse>(); var resourceType = group.GetResourceType(); // 构建针对当前实体类型的Func和Expression类型 var functionType = typeof(Func<,>).MakeGenericType(resourceType, typeof(bool)); var expressionType = typeof(Expression<>).MakeGenericType(functionType); // 获取DbSet<resourceType> var contextSetMethod = _context.GetType().GetMethod("Set", genericParameterCount: 1, Type.EmptyTypes)! .MakeGenericMethod(resourceType); var dynamicContext = contextSetMethod.Invoke(_context, null); // 获取Queryable的SingleOrDefault方法(带谓词的重载) var dbSetMethod = typeof(Queryable).GetMethods() .First(m => m.Name == "SingleOrDefault" && m.GetParameters().Length == 2) .MakeGenericMethod(resourceType); foreach (var member in group.Members) { // 生成匹配当前实体类型的表达式 var funcExpr = BuildDynamicExpression(resourceType, member.MemberId); // 调用Queryable.SingleOrDefault(静态方法,第一个参数为null) var result = dbSetMethod.Invoke(null, new object[] { dynamicContext, funcExpr }); if (result is null || !resourceType.IsInstanceOfType(result)) throw new Exception($"查询失败!结果:{result}"); members.Add((IGroupMember)result); } response.Members = members;
关键修正点说明
- 切换到Queryable:确保表达式被转换为SQL语句在数据库端执行,避免全表加载到内存。
- 匹配实体类型的表达式:为DbSet
生成对应的谓词表达式,解决类型不匹配问题。 - 正确调用静态方法:Queryable的方法是静态扩展方法,调用时第一个参数为null,后续传入DbSet和表达式。
- 避免Expression.Invoke:直接构建属性访问表达式,确保EF Core能正确解析并生成SQL。
内容的提问来源于stack exchange,提问作者Fakima
相关产品推荐
相关产品推荐

