【问题标题】:EF Core + enum parameter in where queryEF Core + enum 参数在 where 查询
【发布时间】:2021-11-13 19:16:47
【问题描述】:

我正在努力将枚举添加到我的查询中的 where 条件。

我的班级有以下定义:

public enum Status
{
  Pending,
  Confirmed
}

public class Deposit
{
  public Status Status { get; set; }
}

每当我添加带有原始枚举值的where 条件时,如下例所示,它可以完美运行:

query.Where(d => d.Status == Status.Completed);

// Generated query:
Executed DbCommand (40ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT d.*
FROM deposit AS d
WHERE d.status = 'Completed'

每当我尝试将此枚举值添加为参数时,都会在以下查询中失败:

query.Where(d => d.Status == input.Status);

// Generated query:

Failed executing DbCommand (244ms) [Parameters=[@__searchInput_Status_Value_0='Completed' (Nullable = false)], CommandType='Text', CommandTimeout='30']
SELECT d.*
FROM deposit AS d
WHERE d.status = @__searchInput_Status_Value_0

如果我尝试在创建模型时转换此枚举,我仍然会遇到同样的错误,无论是 string 还是 int 转换:

对于字符串转换:

modelBuilder.Entity<Deposit>()
  .Property(d => d.Status)
  .HasConversion(new EnumToStringConverter<Status>());

Npgsql.PostgresException (0x80004005): 42883: operator does not exist: enum_deposit_status = text

对于 int 转换:

modelBuilder.Entity<Deposit>()
  .Property(d => d.Status)
  .HasConversion<int>();

Npgsql.PostgresException (0x80004005): 42883: operator does not exist: enum_deposit_status = integer

有人可以解释一下吗? 谢谢大家!! :)

【问题讨论】:

  • “在以下查询中失败”。在这种情况下,您看到了什么错误?
  • 什么是enum_deposit_status?如果是PostgreSQL enum type,则需要特殊的mapping in Npgsql provider。在使用stringint 转换时,您必须更改数据库列类型。
  • @Sasha 我看到的错误是我上面显示的这个错误:“运算符不存在:enum_deposit_status = ”。还有一个提示:“没有运算符与给定的名称和参数类型匹配。您可能需要添加显式类型转换。”
  • @IvanStoev 映射没有帮助。错误仍然存​​在。每当添加一个值作为原始比较时,它都会起作用。参数比较不行,好像
  • @Kiwanax 如果你这样做 query.Where(d =&gt; d.Status == (int)input.Status); 会发生什么?

标签: c# enums entity-framework-core


【解决方案1】:

这似乎是 PostgreSQL EF Core 提供程序中的一个问题。

以下解决方法应该可以解决它,但存在版本限制;请参阅下面的注释。

地图:

modelBuilder.Entity<Deposit>()
  .Property(d => d.Status)
  .HasConversion(new EnumToStringConverter<Status>());

代码:

var statusFilter = new[] { input.Status };
query.Where(d => statusFilter.Contains(d.Status));

有关受影响版本的说明

上述解决方法适用于 Npgsql.EntityFrameworkCore.PostgreSQL 版本 3.0、5.0(希望是 6.0,没有检查)

版本 3 和 5 对代码的翻译不同:

  • 3.0(使用 EF 3.x)

    info: Microsoft.EntityFrameworkCore.Database.Command[20101]
          Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
          SELECT d.*
          FROM deposit AS d
          WHERE d.status IN ('Completed')
    
  • 5.0(使用 EF 5.x)

    info: Microsoft.EntityFrameworkCore.Database.Command[20101]
          Executed DbCommand (15ms) [Parameters=[@__statusFilter_0='?' (DbType = Object)], CommandType='Text', CommandTimeout='30']
          SELECT d.*
          FROM deposit AS d
          WHERE b.status = ANY (@__statusFilter_0)
    

它在 3.1 中不起作用;它几乎失败了same error

  • 3.1(使用 EF 3.x)
    fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
          Failed executing DbCommand (18ms) [Parameters=[@__statusFilter_0='?' (DbType = Object)], CommandType='Text', CommandTimeout='30']
          SELECT d.*
          FROM deposit AS d
          WHERE b.status = ANY (@__statusFilter_0)
    fail: Microsoft.EntityFrameworkCore.Query[10100]
          An exception occurred while iterating over the results of a query for <...>.
          Npgsql.PostgresException (0x80004005): 42883: operator does not exist: character varying = integer
    

【讨论】:

  • 3.0.0 版与您的解决方法一起使用!非常感谢!
  • 太棒了!很高兴它成功了!
【解决方案2】:

如果将来有人(包括我自己)在过滤 EF Core 中映射为字符串的 Postgres 枚举数组时遇到问题,我只想明确指出,上述解决方法也适用于数组,即:

这不起作用

query.Where(d => d.SupportedDepositTypes.Contains(DepositType.RecurringDeposit));

但是这行得通

var filterValue = DepositType.RecurringDeposit;
query.Where(d => d.SupportedDepositTypes.Contains(filterValue));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-16
    • 2021-08-26
    • 2020-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    相关资源
    最近更新 更多