【问题标题】:Lambda expression - For a Select NewLambda 表达式 - 对于 Select New
【发布时间】:2023-03-04 16:35:01
【问题描述】:

我正在尝试从 IQueryable 对象创建自定义集合,我正在尝试执行 select 语句,但出现错误,无法转换为 store 表达式。我是 Lambda 表达式的新手。请帮我解决这个问题。

在 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()
                   })

【问题讨论】:

  • 基本上 EF 或您使用的任何 DB linq 提供程序都不知道如何将您的方法转换为 SQL。尝试将AsEnumerable 放在Select 之前,这样它就会在内存中运行您的代码。

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


【解决方案1】:

我想您正在使用实体框架或类似的 O/R 映射器。

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

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

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

在使用自定义表达式进行选择之前,您只需在 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() 方法。


根据下面的 cmets 进行编辑:

以上所有内容仍然有效,但在 cmets 中您说您的函数需要返回 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 的查询时进行大写,例如在将显示您的数据的视图中.或者一种选择是在LoggerModelEvent 属性设置器中应用大写:

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

    public string Event
    { 
        get { return event; }
        set { event = FirstCharToUpper(value); }
    }
    // ...
}

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

【讨论】:

  • 感谢您的解释,但是有一个问题。如果我想返回一个 PagedList ,它接受带有页码和每页记录总数的 IQueryable - 它不允许吗?由于性能,我选择 IQueryable 而不是 IEnumerable,并且只从数据库中获取有限的记录。所以我不能写一个让 SQL 理解的表达式?
  • return new PagedList( logDB.PELoggers .Where(c => (c.SubscriberCode == SubscriberCode)).OrderByField(sortBy, ascendingOrder).Select(c => new LoggerModel() { DateTime = c.DateTime.Value, Event = c.Event.FirstUpper() }) , 1, 100);
  • 在这种情况下,考虑到您的 FirstCharToUpper() 方法非常简单,并且使用实体框架可以转换为 SQL 的方法,我建议摆脱它并在 LINQ 中使用 ToUpper 和 Substring询问。我用一个例子更新了答案。假设您使用的是最新版本的 Entity Framework。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-19
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多