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

使用C# Expressions为Entity Framework构建Array.All表达式

动态构建Linq表达式实现指定WHERE子句逻辑

实体类定义

public class Report
{
    public string Year { get; set; }
    public ICollection<Documents>? Documents { get; set; }
}

public class Documents
{
    public string Year { get; set; }
    public Report? Report { get; set; }
    public string Type { get; set; }
}

目标Linq查询逻辑

需要实现的查询逻辑等价于:

query.Where(x => x.Report.Documents.All(c => (c.Type == "R" || c.Type == "RX") && c.Year == x.Report.Year))

现有待完善代码

private Expression GetExpression(Expression memberExpression)
{
   Expression<Func<ICollection<Documents>, bool>> containsExpr 
                    = (ICollection<Documents> q) => q.All((Func<Documents, bool> )null);
   var containsMethod = (containsExpr.Body as MethodCallExpression).Method;
                       Expression<Func<Documents, bool>> contains = x => x.Type =="R";
                      
   MemberExpression collectionPropertyAccessor = Expression.Property(memberExpression, "Documents");
  var targetCodesContains = Expression.Call(containsMethod, collectionPropertyAccessor, contains);
  return  binaryExpression =  Expression.And(targetCodesContains, targetCodesContains);
}

完善后的代码

private Expression GetExpression(Expression memberExpression)
{
    // 获取Enumerable.All的泛型方法定义
    var allMethodDefinition = typeof(Enumerable).GetMethods()
        .Where(m => m.Name == "All" && m.GetParameters().Length == 2)
        .First()
        .MakeGenericMethod(typeof(Documents));

    // 构建Documents类型的参数c
    var docParam = Expression.Parameter(typeof(Documents), "c");

    // 构建c.Type == "R" || c.Type == "RX"的表达式
    var typeR = Expression.Equal(Expression.Property(docParam, "Type"), Expression.Constant("R"));
    var typeRX = Expression.Equal(Expression.Property(docParam, "Type"), Expression.Constant("RX"));
    var typeCondition = Expression.OrElse(typeR, typeRX);

    // 构建c.Year == x.Report.Year的表达式(memberExpression对应x.Report)
    var reportYear = Expression.Property(memberExpression, "Year");
    var docYear = Expression.Property(docParam, "Year");
    var yearCondition = Expression.Equal(docYear, reportYear);

    // 合并条件生成All方法的谓词Lambda
    var allPredicate = Expression.Lambda<Func<Documents, bool>>(
        Expression.AndAlso(typeCondition, yearCondition), 
        docParam);

    // 获取x.Report.Documents属性表达式
    var documentsCollection = Expression.Property(memberExpression, "Documents");

    // 生成All方法调用表达式
    return Expression.Call(allMethodDefinition, documentsCollection, allPredicate);
}

关键修改说明

  • 严谨获取All方法:替换原代码中通过表达式树提取方法的方式,直接从Enumerable类获取泛型方法定义,避免类型匹配异常。
  • 构建完整谓词逻辑:
    1. 创建Documents类型的参数c,对应Lambda表达式的输入参数。
    2. 分别实现类型判断和年份匹配的子表达式,再用AndAlso合并为完整条件。
  • 移除无效逻辑:删除原代码中无意义的重复Expression.And调用,替换为实际的All方法调用表达式。

内容的提问来源于stack exchange,提问作者dawid debinski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:20:24