EF Core 内存中数组映射

EF Core In-Memmory Array mapping

我在数据库中有一个字符串数组列

ALTER TABLE sample ADD languages VARCHAR[] NULL;

映射到模型:

public string[] languages { get; set; }

将 EF Core 与 PostgreSQL (Npgsql.EntityFrameworkCore.PostgreSQL 2.2.0) 一起使用是开箱即用的。

但是,当我想使用 In-Memmory (Microsoft.EntityFrameworkCore.InMemory 2.2.4) 测试 DbContext 时,出现了这个错误:

System.InvalidOperationException:无法映射 属性 'sample.languages',因为它的类型 'string[]' 不受支持,或者一个有效的实体类型。显式映射此 属性,或使用“[NotMapped]”属性或使用 'OnModelCreating'.

中的 'EntityTypeBuilder.Ignore' 忽略它

因此,将此添加到模型构建器配置可解决内存错误:

 builder.Property(p => p.languages)
                    .HasConversion(
                        v => string.Join("'", v),
                        v => v.Split(',', StringSplitOptions.RemoveEmptyEntries));

但是提出了一个新的(Npgsql):

Can't cast database type character varying[] to String at Npgsql.NpgsqlDefaultDataReader.GetFieldValue[T](Int32 column)

你有什么提示吗?

没有多少数据库支持开箱即用的数组类型列。实际上 PostgreSQL 可能是目前支持的数据库中唯一一个这样做的。根据最初的异常,显然 in-memory 数据库也不支持它(当前)。

EF Core 为每种数据库类型构建一个单独的模型。每个数据库提供者都公开了 DatabaseFacade 的扩展方法,如 IsSqlServer()IsNpgsql()IsInMemory() 等,可以在 OnModelCreating 中使用它来有条件地为一个数据库配置不同的映射如果需要,特定的数据库类型。

预期的用法是这样的:

modelBuilder.Entity<Sample>(builder =>
{
    if (!Database.IsNpgsql()) // <--
    {
         builder.Property(p => p.languages)
             .HasConversion(
                 v => string.Join("'", v),
                 v => v.Split(',', StringSplitOptions.RemoveEmptyEntries));    
    }
});

如果您使用单独的 classes 实现 IEntityTypeConfiguration<TEntity> 来配置模型,那么您应该将 Database 传递给它们的构造函数并存储在 class 成员中,因为传递给 Configure 方法的 EntityTypeBuilder<TEntity> 不提供此类信息。