You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态数据库调用时抛出ArgumentException异常的技术求助

问题分析与解决方案

核心问题

你的代码存在几个关键错误,导致了类型转换异常:

  1. 错误使用Enumerable.SingleOrDefault而非Queryable.SingleOrDefault,前者针对内存集合操作,后者才是EF Core用于数据库查询的扩展方法。
  2. 构建SingleOrDefault泛型方法时,错误用表达式类型作为泛型参数,而非实体类型(resourceType)。
  3. 生成的谓词表达式类型不匹配:DbSet需要Expression<Func<resourceType, bool>>,但你生成的是Func<IGroupMember, bool>。
  4. 使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:42:34