【问题标题】:Need help converting a lambda to an expression tree需要帮助将 lambda 转换为表达式树
【发布时间】:2017-09-17 02:19:44
【问题描述】:

我已经玩了好几个小时了,并且可以使用新的眼睛。好吧,在表达树方面比我更有经验的人。曲线很陡!

考虑以下内容。 (可行,但我需要将 Accounts 作为字符串传入。Accounts 是 Account 列表)

repo = repo.Where(x => x.Accounts.FirstOrDefault().Id == AccountId);

这是我目前所拥有的。

            var parameterExp = Expression.Parameter(typeof(Boat), "x");
            var propertyExp = Expression.Property(parameterExp, "Accounts");

            MethodInfo method1 = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).First(m => m.Name == "FirstOrDefault");

            // This gives me a Queryable of Account FirstOrDefault
            var specificMethod = method1.MakeGenericMethod(propertyExp.Type);

            // right here is where I am getting stuck
            var firstOrDefaultAccountExpression = // I need to get an Account so I can query against the Id ??


            MethodInfo method = typeof(long).GetMethod("Equals", new[] { typeof(long) });
            var someValue = Expression.Constant(AccountId, typeof(long));
            var containsMethodExp = Expression.Call(firstOrDefaultAccountExpression , method, someValue);

            Expression<Func<Boat, bool>> predicate = Expression.Lambda<Func<Boat, bool>>
                         (containsMethodExp, parameterExp);


            repo = repo.Where(predicate);

我能够让此代码在常规字符串成员上工作。我似乎无法弄清楚名单。最终,我试图找回 AccountId = long 的 Boat 列表

提前致谢!

【问题讨论】:

  • 您只关心每艘船的第一个帐户吗?
  • 是的,它实际上可能是 Singe 而不是 FirstOrDefault。船只将永远只有一个与之相关的帐户。该帐户是船主

标签: c# linq lambda tree expression


【解决方案1】:
var parameterExp = Expression.Parameter(typeof(Boat), "x");
Expression propertyExp = Expression.Property(parameterExp, "Accounts");

Type elementType = propertyExp.Type.GetGenericArguments()[0];

MethodInfo method1 = typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static).First(m => m.Name == "FirstOrDefault");

// This gives me a Queryable of Account FirstOrDefault
var specificMethod = method1.MakeGenericMethod(elementType);

//propertyExp = Expression.TypeAs(propertyExp, typeof(IEnumerable<>).MakeGenericType(elementType));

var firstOrDefaultAccountExpression = Expression.Call(specificMethod, propertyExp);

var idExpr = Expression.PropertyOrField(firstOrDefaultAccountExpression, "Id");

MethodInfo method = typeof(long).GetMethod("Equals", new[] { typeof(long) });
var someValue = Expression.Constant(AccountId, typeof(long));
var containsMethodExp = Expression.Call(idExpr, method, someValue);

Expression<Func<Boat, bool>> predicate = Expression.Lambda<Func<Boat, bool>>
             (containsMethodExp, parameterExp);

repo = repo.Where(predicate);

List&lt;&gt; 必须转换为 IEnumerable&lt;&gt; 才能调用 FirstOrDefault 我发誓如果没有演员表它就不能工作,但现在它工作了,奇怪。所以我注释掉了这条线。但是在这两个版本中,它都能够在 linq2sql 中生成 sql 代码,我对此进行了测试。您不需要 Queryable 来访问 Accounts 属性(我不确定是否可以拥有)。查看代码的第一行,即非表达式查询。即使在那里FirstOrDefault 也是Enumerable 的一种方法。它的目的是通过定义表达式来定义转换,而不是真正做任何事情的函数。

【讨论】:

  • 更新了你的帖子。否则我无法添加图片
  • 有效!你是我的英雄!谢谢安东宁!
  • " 其目的是通过定义表达式来定义转换,而不是函数实际做任何事情。"感谢您的澄清。我不确定 Queryable vs Enumerable 是否在 Expressions 中击中了数据库。再次,陡峭的学习曲线。
猜你喜欢
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
相关资源
最近更新 更多