尝试进行动态数据库调用时出现异常

问题描述 投票:0回答:1

我有一个包含成员的小组课程,这些成员可以属于不同的班级类型。

与此相关的所有其他功能都有效,我只缺少数据库调用,对此我已经没有想法了。

我的代码如下:

response = group.MapEntity<GroupDataResponse>(); //Irrelevant for this question (kept due to comment about it).

var resourceType = group.GetResourceType();

var functionType = typeof(Func<,>).MakeGenericType(typeof(IGroupMember), typeof(bool));

var expressionType = typeof(Expression<>).MakeGenericType(functionType);

var contextSetMethod = _context.GetType().GetMethod("Set", genericParameterCount: 1, Array.Empty<Type>())!.MakeGenericMethod(resourceType);

var dbSetMethod = typeof(Enumerable).GetMethods().FirstOrDefault(x => x.Name == "SingleOrDefault")!.MakeGenericMethod(expressionType);
            
var dynamicContext = contextSetMethod.Invoke(_context, null);
            
foreach (var member in group.Members)
{
    var func = BuildExpression(member.MemberId);
    var result = dbSetMethod.Invoke(dynamicContext, new object?[] { func });
                
    if (result is null || result.GetType() != resourceType)
        throw new Exception($"Something went wrong!!!!! {result}");
                
    members.Add((IGroupMember)result);
}
response.Members = members;

异常发生在

dbSetMethod.Invoke(...)

例外:

System.ArgumentException:“System.Linq.Expressions.Expression1”1[System.Func'2[Trasolu.Domain.Common.IGroupMember,System.Boolean]]”类型的对象无法转换为“System.Collections.Generic”类型.IEnumerable'1[System.Linq.Expressions.Expression'1[System.Func`2[Trasolu.Domain.Common.IGroupMember,System.Boolean]]]'。

我想要的是对数据库进行动态调用,循环中的

func
是一个 lambda 表达式,我想在
dbSetMethod
上运行以确保我只获取具有给定 id 的实体.

这是我尝试运行的函数。

private Func<IGroupMember, bool> BuildExpression(int id)
{
    Expression<Func<IGroupMember, int>> queryFunction = x => x.Id;
    var paramExpr = Expression.Parameter(typeof(IGroupMember));
    var varExpr = Expression.Constant(id, typeof(int));
    var equalExpr = Expression.Equal(
        left: Expression.Invoke(queryFunction, paramExpr),
        right: varExpr);
    var lambda = Expression.Lambda<Func<IGroupMember, bool>>(equalExpr, paramExpr);
    return lambda.Compile();
}
c# reflection entity-framework-core
1个回答
0
投票

EF Core 不支持解析任意编译树。它只能解析正常的表达式树。

您需要首先以正常方式创建表达式。最简单的方法是使用泛型。

private Expression<Func<T, bool>> BuildExpression<T>(int id) where T : IGroupMember
{
    Expression<Func<IGroupMember, bool>> queryFunction = x => x.Id == id;
    return queryFunction;
}

然后你可以使用另一个函数来调用它。如果您愿意,您也可以将这两个功能组合成一个函数。

private static object GetMember<T>(DbContext dbContext, int id) where T : IGroupMember
{
    return dbContext.Set<T>().SingleOrDefault(BuildExpression(id));
}

最后动态调用该函数。您现在只需要构造一个动态调用,而不是整个链。

var functionType = typeof(Func<,,>).MakeGenericMethod(typeof(DbContext), typeof(int), resourceType);
var func = this.GetType()
    .GetMethod(nameof(GetMember), BindingFlags.Static | BindingFlags.NonPublic)
    .MakeGenericMethod(resourceType)
    .CreateDelegate<Func<DbContext, int, object>>(this);
            
foreach (var member in group.Members)
{
    var result = (IGroupMember)func.Invoke(_context, member.MemberId);
    members.Add((IGroupMember)result);
}
response.Members = members;


© www.soinside.com 2019 - 2024. All rights reserved.