Lambda表达式 - 用于选择新建

Dil*_*lip 0 c# linq collections lambda c#-4.0

我正在尝试从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;
}
Run Code Online (Sandbox Code Playgroud)

调用表达式

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()
                   })
Run Code Online (Sandbox Code Playgroud)

Ber*_*nig 5

我想你正在使用Entity Framework或一个熟悉的O/R映射器.

想想你在这里做了什么:你正在编写一个应该针对你的数据库执行的LINQ查询.为此,它会将您的LINQ查询转换为SQL查询,然后对您的数据库执行.

但是FirstCharToUpper()代码中的自定义方法.您的数据库对此一无所知,因此您的O/R映射器的LINQ提供程序无法将其转换为SQL中有意义的任何内容,因此您会收到错误.

因此,您需要做的是首先对数据库"完成"查询以将结果保存在内存中,然后应用任何进一步的处理,这些处理只能在内存集合中的代码边界内完成.

您可以通过.AsEnumerable()在使用自定义表达式执行select之前插入LINQ查询来执行此操作:

logDB.PELoggers
    .Where(c => (c.SubscriberCode == SubscriberCode))
    .OrderByField(sortBy, ascendingOrder)
    .AsEnumerable()
    .Select(c => new LoggerModel()
        {
            DateTime = c.DateTime.Value,
            Event = c.Event.FirstUpper()                       
        })
Run Code Online (Sandbox Code Playgroud)

调用时AsEnumerable(),将执行针对您的数据库的查询,并将结果复制到IEnumerable内存中.在Select()事后将现在已经对内存中的集合对数据库执行了,而不是,因此可以使用自定义FirstCharToUpper()的方法.


根据您的评论进行编辑:

以上所有内容仍然有效,但在评论中,您说您的功能需要返回IQueryable.在您的情况下,您的FirstCharToUpper()方法正在做的非常简单,LINQ到实体提供程序确实支持像ToUpper和的方法Substring.所以我建议简单地删除你的帮助器方法,而不是使用Entity Framework可以转换为有效SQL的方法编写你的LINQ查询来做到这一点:

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)                       
        })
Run Code Online (Sandbox Code Playgroud)

这将导致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
    };
Run Code Online (Sandbox Code Playgroud)

如果您不希望在LINQ查询中完成此操作,则需要在稍后执行对DB的查询时执行大写,例如在将显示数据的视图中.或者一个选项可以是在您的Event属性设置器中应用大写LoggerModel:

public class LoggerModel
{
    // ...
    private string event;

    public string Event
    { 
        get { return event; }
        set { event = FirstCharToUpper(value); }
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是没有办法让自定义函数在LINQ-to-Entities查询中工作.