EF Core In-Memmory Array mapping

Luk*_*988 3 entity-framework npgsql ef-core-2.2

I have a string array column in database

ALTER TABLE sample ADD languages VARCHAR[] NULL;
Run Code Online (Sandbox Code Playgroud)

which is mapped to model:

public string[] languages { get; set; }
Run Code Online (Sandbox Code Playgroud)

Using EF Core with PostgreSQL (Npgsql.EntityFrameworkCore.PostgreSQL 2.2.0) works out of the box.

However, when I want to test DbContext using In-Memmory (Microsoft.EntityFrameworkCore.InMemory 2.2.4) I got this error:

System.InvalidOperationException: 无法映射属性“sample.languages”,因为它的类型“string[]”不是受支持的基本类型或有效的实体类型。显式映射此属性,或使用 '[NotMapped]' 属性或使用 'OnModelCreating' 中的 'EntityTypeBuilder.Ignore' 忽略它。

因此,将其添加到模型构建器配置中可以解决 In-Memory 错误:

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

但引发了新的(Npgsql):

无法在 Npgsql.NpgsqlDefaultDataReader.GetFieldValue[T](Int32 列)处将数据库类型字符变化 [] 转换为字符串

请问您有什么提示吗?

Iva*_*oev 6

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

EF Core 为每种数据库类型构建单独的模型。每个数据库提供程序公开的扩展方法DatabaseFacadeIsSqlServer()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));    
    }
});
Run Code Online (Sandbox Code Playgroud)

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