繁体   English   中英

EF Core 5.0 - 如何使用列表播种实体<string>迁移中的财产?</string>

[英]EF Core 5.0 - How to seed entity with List<string> property in a migration?

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

我有一个具有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 ,我会得到这个 output:

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>属性?


编辑:我认为这个问题与实体框架 - 代码优先 - 无法存储列表等其他问题不同,因为如果我在空白数据库上启动它,我的程序可以正常工作(使用 PostgreSQL,它会创建一个text[]类型的Names列 [ text[] ,如您所料)。 问题是当我使用dotnet ef迁移工具时。

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

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

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


OLD:问题不在于HasData功能本身。 根本问题是 EF Core 本身并不知道如何将List<string>存储到数据库中,因此它失败了。

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

go 的最佳方法可能是使用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 class ,它可以使用我想要的任何自定义逻辑播种我需要的数据,而没有任何限制HasData有(参考: https://docs.microsoft.com/en-us/ef/core/modeling/data-seeding#limitations-of-model-seed-data

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM