Lambda表达式 - 用于选择新建

时间:2017-01-03 15:19:04

标签: c# linq c#-4.0 collections lambda

我正在尝试从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()
                   })

1 个答案:

答案 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提供程序确实支持ToUpperSubstring等方法。所以我建议简单地删除你的帮助方法,而是编写你的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查询中工作。