c# - EF Core 5.0 - 如何在迁移中使用 List<string> 属性播种实体?

标签 c# entity-framework-core

我花了几个小时试图解决这个问题,但可以找到解决方案。

我有一个带有 List<string> 的实体属性,我想对其进行数据播种。我成功使用 modelBuilder.Entity<T>.HasData() ,但它不适用于 dotnet ef migrations .

这是我的实体:

public class MyEntity
{
    public int Id { get; set; }

    public List<string> Names { get; set; }
}

这是我的 DbContext.OnModelCreating覆盖:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>()
        .HasData(
            new MyEntity { Id = 1, Names = new List<string> { "text1", "text2" } },
            new MyEntity { Id = 2, Names = new List<string> { "text1", "text2", "text3" } },
            new MyEntity { Id = 3, Names = new List<string> { "text1", "text2" } },
            new MyEntity { Id = 4, Names = new List<string> { "text1", "text2" } },
            new MyEntity { Id = 5, Names = new List<string> { "text1", "text2", "text3" } });
}

如果我运行我的应用程序,它会创建表并使用所需的值为其播种。但如果我运行 dotnet ef migrations add AddMyEntities --project src/MyProject --startup-project src/MyProject.Api ,我得到这个输出:

Build started...
Build succeeded.
System.NotSupportedException: The type mapping for 'List<string>' has not implemented code literal generation.
   at Microsoft.EntityFrameworkCore.Storage.CoreTypeMapping.GenerateCodeLiteral(Object value)
   at Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.UnknownLiteral(Object value)
   at Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.Literal(Object[,] values)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationOperationGenerator.Generate(InsertDataOperation operation, IndentedStringBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationOperationGenerator.Generate(String builderName, IReadOnlyList`1 operations, IndentedStringBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGenerator.GenerateMigration(String migrationNamespace, String migrationName, IReadOnlyList`1 upOperations, IReadOnlyList`1 downOperations)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The type mapping for 'List<string>' has not implemented code literal generation.

我怎样才能播种一个简单的List<string>属性(property)?


编辑:我认为这个问题与其他问题不同,例如 Entity Framework - Code First - Can't Store List因为如果我在空白数据库上启动我的程序,它就可以正常工作(使用 PostgreSQL,它会创建 Names 类型的 text[] 列,如您所料)。问题是当我使用dotnet ef时迁移工具。

最佳答案

编辑: OP 提到它使用 PostgreSQL 和相应的 EF 提供程序,因此问题不是缺失值转换器。

该问题似乎与 EF Core 本身的限制有关。迁移脚手架过程当前使用内置的硬编码 CSharpHelper知道如何为一组封闭类型生成 C# 文字的类。例如,它知道如何生成object[]文字,但不是 IEnumerable<> 。 (引用:dotnet/efcore#12979)。看来现在提供者可以为其他类型添加代码文字的生成,并且我可以发现它是为 npgsql/efcore.pg#0deb6a23 中的某些类型添加的。 ,但不适用于 List<>据我所知...但我可能是错的,因为我自己没有测试过这些。

我的建议?要么使用string[]或沟HasData并提供一些自定义播种逻辑。


旧:问题不在于 HasData功能本身。根本问题是 EF Core 本身并不知道如何存储 List<string>写入数据库,因此失败。

您可以做的是定义一个自定义 ValueConverter指示 EF Core 如何将该特定属性存储到数据库列中(您可以查看 EF Core docs 有关此主题的信息)。

也许最好的方法是使用 Newtonsoft JSONConvert 定义此转换。 :

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>()
        .Property(p => p.Names)
        .HasConversion(
            listOfStringNames => JsonConvert.SerializeObject(listOfStringNames),
            namesJsonRepresentation => JsonConvert.DeserializeObject<List<string>>(namesJsonRepresentation));
        .HasData(
            new MyEntity { Id = 1, Names = new List<string> { "text1", "text2" } },
            new MyEntity { Id = 2, Names = new List<string> { "text1", "text2", "text3" } },
            new MyEntity { Id = 3, Names = new List<string> { "text1", "text2" } },
            new MyEntity { Id = 4, Names = new List<string> { "text1", "text2" } },
            new MyEntity { Id = 5, Names = new List<string> { "text1", "text2", "text3" } });
}

作为旁注,我想提一下,尽管 HasData很好,根据我个人的经验,最好自己写DatabaseInitializer类将使用我想要的任何自定义逻辑来播种我需要的数据,而没有 HasData 的任何限制有(引用:https://learn.microsoft.com/en-us/ef/core/modeling/data-seeding#limitations-of-model-seed-data)

关于c# - EF Core 5.0 - 如何在迁移中使用 List<string> 属性播种实体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66191705/

相关文章:

entity-framework-core - 如何使用 Hotchocolate 和 EF Core 指定默认排序?

c# - ASP.NET 如何在请求中获取自定义 header ?

c# - Entity Framework 断开连接的图形和导航属性

c# - 1. 路由参数中的正斜杠

c# - 多对多 EF Core 关系 - 为什么它尝试将实体插入到不同的表中?

asp.net-core - 如何拥有与 "Id"不同名称的主键

c# - 南希.ViewEngines.ViewNotFoundException : Unable to locate view 'index.cshtml'

c# - 在 Form_Load 中使用 AnimateWindow()

c# - 实体类型 'Microsoft.AspNetCore.Identity.IdentityRole' 处于影子状态

.net-core - 如何在搭建数据库后运行迁移