EF Core + where 查询中的枚举参数

EF Core + enum parameter in where query

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

我的 class 定义如下:

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

如果我尝试在我的模型创建中转换此枚举,我会一直遇到相同的错误,使用 stringint 转换:

对于字符串转换:

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

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

这似乎是 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
    

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

这行不通

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

但这行得通

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