【问题标题】:Build an lambda Expression tree with a specific field in a linked entity在链接实体中构建具有特定字段的 lambda 表达式树
【发布时间】:2019-09-27 13:38:22
【问题描述】:

数据模型

public class TABLE
    {
        [Key]
        public int ID { get; set; }
        public int ONEFIELD { get; set; }

        // -------------------- ForeignKey --------------------
        [ForeignKey("People")]
        public long PeopleID { get; set; }
        public virtual People People { get; set; }
    }

    public class People
    {
        [Key]
        public long PeopleID { get; set; }
        public int CountryID { get; set; }
    }

我需要构建一个 lambda 来查询这个模型:

获取 TABLE.ONEFIELD = 1 和 TABLE.PEOPLE.COUNTRYID = 6

LINQ 等效项

_context.TABLEs
  .Where(e => e.ONEFIELD == 1)
  .Include(e => e.People)
  .Where(i=>i.People.CountryID == 6);

我的尝试

  public static Expression<Func<TEntity, bool>> BuildLambda<TEntity>(OBJTYPE obj)
        {

        var item = Expression.Parameter(typeof(TEntity), "table");
        Expression query = null;


        // 1
        var prop1 = Expression.Property(item, "ONEFIELD");
        var value1 = Expression.Constant(1);
        var equal1 = Expression.Equal(prop1, value1);
        var lambdaFIELDONE = Expression.Lambda<Func<TEntity, bool>>(equal1, item);
        query = lambdaFIELDONE.Body;

        // 2
        var prop2 = Expression.Property(item, typeof(People).Name + ".CountryID");
        var value2 = Expression.Constant(6);
        var equal2 = Expression.Equal(prop2, value2);
        var lambdaCOUNTRYID = Expression.Lambda<Func<TEntity, bool>>(equal2, item);
        query = Expression.And(query, lambdaCOUNTRYID);

    }

但我收到此错误

System.ArgumentException:没有为类型“SOLUTION.Models.TABLE”定义实例属性“People.CountryID”

我不需要 Generic,只需要一个固定的 lambda(而且我不能使用 LINQ)。

我尝试了几种方法来捕捉 People.CountryID 之类的

Expression.Property(item1, typeof(People).GetProperty("CountryID"));
Expression.Property(item, typeof(People).Name+"." + typeof(People).GetProperty("CountryID"));
Expression.Property(item, typeof(People).Name + "." + typeof(People).GetProperties().Where(x => x.Name == "CountryID").FirstOrDefault().Name);

没有成功

有什么想法吗?谢谢

【问题讨论】:

  • 需要嵌套两个Expression.Property表达式来表示访问中的每一步。我建议获取 LINQPad 并使用 Dump 方法:您可以创建一个 LambdaExpression&lt;Func&lt;&gt;&gt; 变量并将其转储以查看它是如何构建的。
  • 另外你还有很多错误:1.没有理由创建lambdaFIELDONE只是为了立即拆开得到Body - equal1 body . 2. 您可以在Expression.And 中添加一个 lambda(考虑:q = q && (x => z))——这没有任何意义。您在构建主体后最后创建 lambda。

标签: c# linq lambda expression expression-trees


【解决方案1】:

因此,要构建嵌套属性访问,您必须嵌套访问每个级别的Expressions。然后您可以将测试组合成一个主体,最后为结果创建 lambda:

public static Expression<Func<TEntity, bool>> BuildLambda<TEntity>(OBJTYPE obj) {
    // (TEntity table)
    var parmTable = Expression.Parameter(typeof(TEntity), "table");

    // table.ONEFIELD
    var prop1 = Expression.Property(parmTable, "ONEFIELD");
    // table.ONEFIELD == 1
    var equal1 = Expression.Equal(prop1, Expression.Constant(1));

    // table.People
    var prop2_1 = Expression.Property(parmTable, nameof(People));
    // table.People.CountryID
    var prop2_2 = Expression.Property(prop2_1, "CountryID");
    // table.People.CountryID == 6
    var equal2 = Expression.Equal(prop2_2, Expression.Constant(6));

    // table.ONEFIELD == 1 && table.People.CountryID == 6
    var finalBody = Expression.AndAlso(equal1, equal2);

    // table => table.ONEFIELD == 1 && table.People.CountryID == 6
    return Expression.Lambda<Func<TEntity, bool>>(finalBody, parmTable);
}

使用 LINQPad,您可以创建一个示例 lambda,然后使用 Dump 方法,您会看到创建了一个嵌套的 FieldExpression,这就是您调用 Expression.Property 时创建的内容:

Expression<Func<TEntity, int>> f = t => t.People.CountryID;

f.Dump();

【讨论】:

  • 这行得通!太感谢了。您提高了我对“Expression.Property”的理解,但我仍然需要努力更好地掌握“Expression”。感谢 LINQPAD 的建议,我会试试的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多