SQL to LINQ - 案例语句

Posted

技术标签:

【中文标题】SQL to LINQ - 案例语句【英文标题】:SQL to LINQ - Case Statement 【发布时间】:2020-10-31 15:59:14 【问题描述】:

我是第一次将 SQL 语句重写到 LINQ。我不太确定如何正确写出我的案例陈述。运行时不喜欢我写的方式(我以link 为例)

我的目标是按照案例陈述组织我的数据。请让我知道我可以修改什么来实现我的目标。

我的错误是:


    InvalidOperationException: The LINQ expression 'DbSet<Table>
    .Where(c => c.ID ==(Nullable<int>)10)
    .OrderBy(c => c.column1)
    .ThenBy(c => _sortOrder_0.TryGetValue(
    key: c.column3,
    value:_order_1)?_order_1:_defaultOrder_2)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), ToList(), or ToListAsync()

原始 SQL 查询:


    SELECT column1, column2, column3 from table where ID = # order by column1, 
    Case column3 When 'X' Then 1 When 'Y' Then 2 When 'Z' Then 3 End

LINQ:

public async Task<IActionResult> Index()

    var sortOrder = new Dictionary<string, int>
        
            "X", 1 ,
            "Y", 2 ,
            "Z", 3 ,
        ;
    var defaultOrder = sortOrder.Max(x => x.Value) + 1;
    int order;
    var dataTest = _context.TableModel
        .Where(x =>
        (x.ID == 10)
        )
        .Select(x => new TableModel
        
            column1 = x.column1,
            column2 = x.column2,
            column3 = x.column3,
        )
        .OrderBy(x => x.column1)
        .ThenBy(x => sortOrder.TryGetValue(x.column3, out order) ? order : defaultOrder)
        .AsNoTracking()
        .ToListAsync();

旁注:我使用 ID = 10 进行测试。感谢您的宝贵时间!

【问题讨论】:

EF 无法将sortOrder.TryGetValue .. 转换为sql,您是否尝试过类似.ThenBy(x =&gt; x.column3 =='X' ? 1 : (x.column3 =='Y' ? 2 : (x.column3 =='Y' ? 3 : defaultOrder))) 的查询或在.Select 之后使用.ToList() 在客户端订购。 不管怎样,Entity Framework 可以直接执行您的原始 SQL 查询。 无需转换为 EF Linq。见docs.microsoft.com/en-us/ef/core/querying/raw-sql @RobertHarvey 是的,我知道。我尝试使用 FromSqlRaw 方法,但它也讨厌这样。它抛出了一个错误,我的列之一不存在 一种选择是从数据库中提取数据,然后在内存中进行排序。 如果您的查询在 SSMS 中工作,它将作为原始查询工作。 【参考方案1】:

尝试在ThenBy 子句中对所有情况使用三元运算符:

 .ThenBy(x => x.column3 == "X" 
      ? 1 
      : x.column3 == "Y" 
          ? 2 
          : x.column3 == "Z" 
                ? 3 
                : defaultOrder)

【讨论】:

【参考方案2】:

这会有点恶心,但是......

context.TableModel.Where(x => x.ID == 10)
    .OrderBy(x => x.column1)
    .ThenBy(x=> x.column3 == "X" ? 1
        : x.column3 == "Y" ? 2
        : x.column3 == "Z" ? 3
        : defaultOrder)
    .AsNoTracking()
    .ToListAsync();

基本上只是一个巨大的嵌套 if 语句。 此外,如果您的表只有三列,则 select 语句是多余的。

我的建议是从您的所有 column3 值中创建一个枚举,然后改为 orderby。它会更有效率,因为 enum 会为每个项目分配 int 值。

【讨论】:

为什么select语句是多余的?可能 OP 只想从表中选择一些字段,而不是全部(我建议在这种情况下创建 DTO,但如果没有 TableModel,则没有足够的信息来说明不需要选择)。 使column3 成为枚举不起作用,因为排序是在数据库上完成的,它是一个字符串而不是一个数值。除非您的意思是他们应该将整数值存储在数据库中。 @guruStron 你是对的,我会修改我的声明。 @juharr 当属性类型为枚举时,实体框架会将值转换为整数。在运行时,可以访问枚举以获取字符串值。 根据 EF 的版本,它可以将数据库中的值转换为内存中的枚举,但它仍然是完成排序的数据库中的字符串。此外,该示例似乎并不详尽,因此您仍然需要一个默认值并指定哪些不是默认值。

以上是关于SQL to LINQ - 案例语句的主要内容,如果未能解决你的问题,请参考以下文章

常用sql语句及案例(oracle)

常用sql语句及案例

常用sql语句及案例(oracle)

常用sql语句及案例(oracle)

pl/sql案例

Linq教程