【发布时间】:2011-05-26 15:09:05
【问题描述】:
我正在玩弄表达式树并试图更好地理解它们是如何工作的。我写了一些我正在使用的示例代码,希望有人可以帮助我。
所以我有这个有点混乱的查询:
/// <summary>
/// Retrieves the total number of messages for the user.
/// </summary>
/// <param name="username">The name of the user.</param>
/// <param name="sent">True if retrieving the number of messages sent.</param>
/// <returns>The total number of messages.</returns>
public int GetMessageCountBy_Username(string username, bool sent)
{
var query = _dataContext.Messages
.Where(x => (sent ? x.Sender.ToLower() : x.Recipient.ToLower()) == username.ToLower())
.Count();
return query;
}
_dataContext 是实体框架数据上下文。这个查询很好用,但不容易阅读。我决定将内联 IF 语句分解为 Func,如下所示:
public int GetMessageCountBy_Username(string username, bool sent)
{
Func<Message, string> userSelector = x => sent ? x.Sender : x.Recipient;
var query = _dataContext.Messages
.Where(x => userSelector(x).ToLower() == username.ToLower())
.Count();
return query;
}
这看起来效果很好,但是有一个问题。因为查询是针对 IQueryable<T> 的,所以这个 LINQ 表达式正在被转换为 SQL 以在数据源处执行。这很好,但正因为如此,它不知道如何处理对userSelector(x) 的调用并引发异常。它无法将此委托转换为表达式。
所以现在我明白了它失败的原因,我想尝试让它发挥作用。我需要做的工作要多得多,但我这样做只是出于纯粹的兴趣。我怎样才能把这个Func 变成一个可以翻译成SQL 的表达式?
我尝试过这样做:
Expression<Func<Message, string>> userSelectorExpression = x => sent ? x.Sender : x.Recipient;
Func<Message, string> userSelector = userSelectorExpression.Compile();
但是,我得到了同样的错误。我想我无法理解表达式。我认为我对上述代码所做的只是编写一个表达式,然后再次将其转换为可执行代码,然后得到相同的错误。但是,如果我尝试在 LINQ 查询中使用userSelectorExpression,它就不能像方法一样被调用。
编辑
对于那些对异常感兴趣的人,这里是:
LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。
我认为这意味着它不能“调用”userSelector 委托。因为,如上所述,它需要将其翻译成表达式树。
当使用真正的方法时,你会得到一个稍微冗长的错误信息:
LINQ to Entities 无法识别方法 'System.String userSelector(Message, Boolean)' 方法,并且此方法无法转换为存储表达式。
【问题讨论】:
-
注意:我知道,最终只使用我的原始查询会简单得多。我只是对表达式如何工作以供将来参考感兴趣。
-
如果你把它作为一个单独的方法会发生什么?
-
@FlyingStreudel,同样的错误。这是因为查询正在被翻译成表达式树。
-
糟糕,我没有注意到 EF 标签。是的,sql不能'
-
我认为问题不在于它不能把它变成一个表达式树,而是它不能把得到的表达式树变成SQL。
标签: c# linq entity-framework delegates linq-to-entities