【问题标题】:How to convert given lambda query to IQueryable如何将给定的 lambda 查询转换为 IQueryable
【发布时间】:2020-03-22 14:24:16
【问题描述】:

我准备了这个 Linq-to-SQL 查询,它需要以 IQueryable 执行,但它失败了。

当我通过调用ToList 转换filteredResult 时,它运行良好,但我需要使用filteredResult 作为IQueryable 并获得如下选择结果。但我得到一个错误

带有语句体的 lambda 表达式不能转换为表达式树

通过下面的链接,但是,如何将下面的查询转换为IQueryable。根据链接,我是否需要写 Func<object,object> 或任何转换查询的示例真的很有帮助。

"A lambda expression with a statement body cannot be converted to an expression tree"

var result = filteredResult.Select(g => {
    var type1 = g.FirstOrDefault(x => x.CategoryId == (int)CategoryEnum.Typ1);
    var type2 = g.FirstOrDefault(x => x.CategoryId == (int)CategoryEnum.Typ2);

return new AutoDetailDto
    {
        MilestoneId = g.Key.MilestoneId,
        MilestoneName = g.Key.MilestoneName,
        PGrade = type1?.GDR,
        PGradeChange = type1?.HighestGDR
        QGrade = type2.GDR,
        QGradeChange = type2?.HighestGDR    
    };
});

【问题讨论】:

    标签: c# linq linq-to-sql


    【解决方案1】:

    单独的功能将无济于事。无论哪种情况,系统都无法确定如何从复杂的 C# 代码生成 SQL。

    试试这个:

    // This is converted to SQl because the lambda, though compe, is a single statement
    var dataResult = filteredResult.Select(g => new {
        type1 = g.FirstOrDefault(x => x.CategoryId == (int)CategoryEnum.Typ1),
        type2 = g.FirstOrDefault(x => x.CategoryId == (int)CategoryEnum.Typ2),
        MilestoneId  = g.Key.MilestoneId,
        MilestoneName = g.Key.MilestoneName
    }).ToArray(); // ToArray() forces execution of the query  
    
    // This select is done entirely in memory
    var result = dataResult.Select (e =>
           new AutoDetailDto
           {
               MilestoneId = e.MilestoneId,
               MilestoneName = e.MilestoneName,
               PGrade = e.type1?.GDR,
               PGradeChange = e.type1?.HighestGDR
               QGrade = e.type2.GDR,
               QGradeChange = e.type2?.HighestGDR    
           });
    

    我认为这应该可行。告诉我。

    编辑:

    奇怪的是,虽然 null 传播运算符是不允许的,但旧的条件 -if 是,所以尝试:

    var dataResult = filteredResult.Select(g => new {
            type1 = g.FirstOrDefault(x => x.CategoryId == (int)CategoryEnum.Typ1),
            type2 = g.FirstOrDefault(x => x.CategoryId == (int)CategoryEnum.Typ2),
            MilestoneId  = g.Key.MilestoneId,
            MilestoneName = g.Key.MilestoneName
        }); // No forcing of execution here
    
    var result = dataResult.Select (e =>
           new AutoDetailDto
           {
               MilestoneId = e.MilestoneId,
               MilestoneName = e.MilestoneName,
               PGrade = e.type1 == null ? null : e.type1.GDR,
               PGradeChange = e.type1 == null ? null :e.type1.HighestGDR
               QGrade = e.type2 == null ? null : e.type2.GDR,
               QGradeChange = e.type2 == null ? null : e.type2.HighestGDR    
           });
    

    【讨论】:

    • 它可以工作,但是我需要作为 IQueryable 执行而不是使用强制执行。
    • 为什么需要这样做?
    • 它的结果集很大,并作为响应为 IQuerable 的 OData 端点执行。
    • 我拆分它的主要原因是允许中间变量type1和type2,这样可以节省代码重复。但是,即使您对此不担心,我也不认为您的“?。”运算符也可以转换为表达式树。
    • 如果没有ToArray,这将不起作用,然后进行第二个查询。我的意思是,它在表达式树上给出了相同的转换失败消息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多