我正在尝试从IQueryable对象创建自定义集合,其中我尝试执行select语句但是获取错误无法转换为存储表达式。我是Lambda Expression的新手。请帮助我解决这个问题。
在c.Event.FirstUpper()
行获取错误public static string FirstCharToUpper(string input)
{
if (String.IsNullOrEmpty(input))
return string.Empty;
var trimmed = input.Trim();
return trimmed.First().ToString().ToUpper() + trimmed.Substring(1);
}
public static Expression<Func<string, string>> GetFirstCaseToUpperExpression()
{
var expression = NJection.LambdaConverter.Fluent.Lambda.TransformMethodTo<Func<string, string>>()
.From(() => StringFormatter.FirstCharToUpper)
.ToLambda();
return expression;
}
调用表达式
return new List<LoggerModel>(
logDB.PELoggers
.Where(c => (c.SubscriberCode == SubscriberCode)).OrderByField(sortBy, ascendingOrder).Select(c => new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = c.Event.FirstUpper()
})
答案 0 :(得分:5)
我想你正在使用Entity Framework或一个熟悉的O / R映射器。
想想你在这里做了什么:你正在编写一个应该针对你的数据库执行的LINQ查询。为此,它会将您的LINQ查询转换为SQL查询,然后对您的数据库执行该查询。
但是FirstCharToUpper()
是代码中的自定义方法。您的数据库对此一无所知,因此您的O / R映射器的LINQ提供程序无法将其转换为SQL中有意义的任何内容,因此您会收到错误。
所以你需要做的就是先完成&#34;对数据库的查询将结果保存在内存中,然后应用任何进一步的处理,只能在内存集合的代码边界内完成。
在使用自定义表达式进行选择之前,只需在LINQ查询中插入.AsEnumerable()
即可完成此操作:
logDB.PELoggers
.Where(c => (c.SubscriberCode == SubscriberCode))
.OrderByField(sortBy, ascendingOrder)
.AsEnumerable()
.Select(c => new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = c.Event.FirstUpper()
})
调用AsEnumerable()
时,将执行针对您的数据库的查询,并将结果复制到内存中的IEnumerable
。之后的Select()
现在已经针对内存中的集合执行,而不再针对数据库执行,因此它可以使用您的自定义FirstCharToUpper()
方法。
根据您的评论进行修改:
以上所有内容仍然有效,但在评论中您说您的函数需要返回IQueryable
。在您的情况下,您的FirstCharToUpper()
方法正在做的非常简单,LINQ-to-Entities提供程序确实支持ToUpper
和Substring
等方法。所以我建议简单地删除你的帮助方法,而是编写你的LINQ查询,用Entity Framework可以转换为有效SQL的方法做到这一点:
logDB.PELoggers
.Where(c => (c.SubscriberCode == SubscriberCode))
.OrderByField(sortBy, ascendingOrder)
.Select(c => new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = c.Event.Substring(0, 1).ToUpper()
+ c.Event.Substring(1)
})
这将导致SQL查询返回Event中的内容,并在数据库中使用大写的第一个字母。
还支持IsNullOrEmpty
检查和你正在做的Trim
(LINQ-to-Entities也支持)我建议将lambda语法更改为LINQ查询语法,以便您可以使用修剪的let
语句,使代码更清晰:
from c in logDB.PELoggers
let trimmedEvent = c.Event.Trim()
where c.SubscriberCode == SubscriberCode
select new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = !string.IsNullOrEmpty(trimmedEvent)
? trimmedEvent.Substring(0, 1).ToUpper()
+ trimmedEvent.Substring(1)
: string.Empty
};
如果您不希望在LINQ查询中完成此操作,则需要在稍后执行对DB的查询时在某个时刻执行大写,例如在将显示数据的视图中。或者,一个选项可能是在Event
的{{1}}属性设置器中应用大写字母:
LoggerModel
但是没有办法让自定义函数在LINQ-to-Entities查询中工作。