2017-09-17 45 views
0

我一直在玩这个小时,并且可以使用一组全新的眼睛。好的比我有更多经验的人表达树木。男人的曲线陡峭!需要帮助将lambda转换为表达式树

请考虑以下事项。 (它的工作原理,但我需要的帐户作为一个字符串传递。账户是客户列表)

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

在此先感谢!

+0

您只关心每艘船的第一个帐户? –

+0

是的,它可能实际上是Singe而不是FirstOrDefault。船只将只有一个相关的帐户。该帐户是船主 – th3monk3y

回答

0
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<>必须被转换为IEnumerable<>到能够调用FirstOrDefault我会发誓,它没有演员没有工作,但现在它工作,很奇怪。所以我评论了这条线。但是在两个版本中,它都能够在linq2sql中生成sql代码,我测试了它。你不需要Queryable来访问Accounts属性(我不确定是否可以)。看看代码的第一行,即非表达式查询。即使在那里,FirstOrDefault也是Enumerable的一种方法。它的目的是通过定义表达式来定义转换,而不是实际做任何事情的功能。

+0

更新了您的帖子。我无法添加图像,否则 – th3monk3y

+0

工程!你是我的英雄!谢谢安东宁! – th3monk3y

+0

“它的目的是通过定义表达式来定义转换,它并不是实际做任何事情的功能。”感谢您的澄清。我不确定Queryable与Enumerable是否在表达式中击中数据库。再次,陡峭的学习曲线。 – th3monk3y