c# - EF Core 5.0 - 如何使用列表播种实体迁移中的财产?
问题描述
我试图解决这个问题需要几个小时,但可以找到解决方案。
我有一个具有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>
属性?
编辑:我认为这个问题与实体框架 - 代码优先 - 无法存储列表等其他问题不同,因为如果我在空白数据库上启动它(使用 PostgreSQL,它会创建一个Names
类型的列text[]
,就像你一样),我的程序可以正常工作会期望)。问题是当我使用dotnet ef
迁移工具时。
解决方案
编辑: OP 提到它使用 PostgreSQL 和相应的 EF 提供程序,所以问题不在于缺少值转换器。
该问题似乎与 EF Core 本身的限制有关。迁移脚手架过程当前使用内置的硬编码CSharpHelper类,该类知道如何为一组封闭的类型生成 C# 文字。例如,它知道如何生成object[]
文字,但不知道IEnumerable<>
. (参考:dotnet/efcore#12979)。似乎现在提供者可以为其他类型添加代码文字的生成,我可以发现它是为npgsql/efcore.pg#0deb6a23中的某些类型添加的,但List<>
据我所知不是......但是我可能是错的,因为我自己没有测试过这些。
我的建议?使用string[]
或放弃HasData
并提供一些自定义播种逻辑。
OLD:问题不在于HasData
功能本身。根本问题是 EF Core 本身并不知道如何将 a 存储List<string>
到数据库中,因此它失败了。
您可以做的是定义一个自定义ValueConverter
,指示 EF Core 如何将该特定属性存储到您的数据库列中(您可以查看有关此主题的EF Core 文档)。
可能最好的方法是使用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 ://docs.microsoft.com/en-us/ef/core/modeling/data-seeding#limitations-of-model-seed-data )
推荐阅读
- python - df_valid 的 IndexError
- android - RadioButton 外发光在开始时被切断
- javascript - 如何通过 PyQuery 选择具有部分类名的标签?
- google-apps-script - 除非在 G-Suite 域上将发布首选项设置为“快速发布”,否则无法访问工作表的工作区添加
- amazon-web-services - 验证此存储桶是否存在。如果存在,请检查生命周期策略,然后尝试发布更改
- r - 如何在 R 中创建 ID 列并将数据随机分配给组
- c# - NEST C# 不返回结果,但查询 DSL 返回结果
- gtk - Gtk.Label 换行未按预期工作
- flutter - 当我在 android studio 中运行我的颤振应用程序时,出现以下错误。我该如何修复它
- azure-media-services - Azure 媒体服务 - v3 覆盖位置问题