C# EF Core 5.0-如何使用列表为实体种子<;字符串>;迁移中的属性?
我花了几个小时试图弄明白这一点,但可以找到解决办法 我有一个具有C# EF Core 5.0-如何使用列表为实体种子<;字符串>;迁移中的属性?,c#,entity-framework-core,C#,Entity Framework Core,我花了几个小时试图弄明白这一点,但可以找到解决办法 我有一个具有列表属性的实体,我想对其进行数据播种。我成功地使用了modelBuilder.Entity.HasData(),但它不适用于dotnet ef迁移 这是我的实体: 公共类MyEntity { 公共int Id{get;set;} 公共列表名称{get;set;} } 下面是我的DbContext.OnModelCreatingoverride: 模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder) {
列表
属性的实体,我想对其进行数据播种。我成功地使用了modelBuilder.Entity.HasData()
,但它不适用于dotnet ef迁移
这是我的实体:
公共类MyEntity
{
公共int Id{get;set;}
公共列表名称{get;set;}
}
下面是我的DbContext.OnModelCreating
override:
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity()
.HasData(
新MyEntity{Id=1,Names=new List{“text1”,“text2”},
新的MyEntity{Id=2,Names=new List{“text1”,“text2”,“text3”},
新MyEntity{Id=3,Names=new List{“text1”,“text2”},
新的MyEntity{Id=4,Names=new List{“text1”,“text2”},
新的MyEntity{Id=5,name=new List{“text1”、“text2”、“text3”});
}
如果我运行我的应用程序,它会创建表并用想要的值为其种子。但是如果我运行dotnet ef migrations add addmyenties--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.
已开始生成。。。
构建成功。
System.NotSupportedException:“List”的类型映射未实现代码文本生成。
位于Microsoft.EntityFrameworkCore.Storage.CoreTypeMapping.GenerateCollateral(对象值)
位于Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.UnknownLiteral(对象值)
位于Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.Literal(对象[,]值)
位于Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationOperationGenerator.Generate(InsertDataOperation操作,缩进StringBuilder)
位于Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationOperationGenerator.Generate(字符串生成器名称、IReadOnlyList`1操作、缩进字符串生成器)
位于Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationGenerator.GenerateMigrationMigrationMigrationName(字符串migrationNamespace、字符串migrationName、IReadOnlyList`1 upOperations、IReadOnlyList`1 downOperations)
位于Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(字符串迁移名称、字符串根命名空间、字符串子命名空间、字符串语言)
位于Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(字符串名称、字符串输出目录、字符串上下文类型、字符串命名空间)
位于Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(字符串名称、字符串输出目录、字符串上下文类型、字符串命名空间)
在Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.c__DisplayClass0_0.b_0()中
在Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.c__DisplayClass3_0`1.b__0()中
位于Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(操作)
“List”的类型映射尚未实现代码文本生成。
如何为简单的列表属性种子
编辑:我认为这个问题与其他问题不同,例如,如果我在空白数据库上启动程序,我的程序工作正常(使用PostgreSQL,它会创建一个Names
列,类型为text[]
,正如您所期望的那样)。问题是当我使用dotnet ef
迁移工具时。编辑:OP提到它正在与相应的ef提供程序一起使用PostgreSQL,因此问题不是缺少值转换器
这个问题似乎与EF核心本身的局限性有关。迁移脚手架过程目前使用一个内置的硬编码类,该类知道如何为一组封闭的类型生成C#literal。例如,它知道如何生成对象[]
文本,但不知道如何生成IEnumerable
。(参考文献:)。似乎现在提供者可以为其他类型的代码文本添加生成,我可以发现它是为中的某些类型添加的,但就我所了解的List
而言,它不是为中的某些类型添加的。。。但我可能是错的,因为我自己没有测试过
我的建议?使用string[]
或ditchHasData
并提供一些自定义种子设定逻辑
OLD:问题不在于HasData
功能本身。潜在的问题是EF Core本身不知道如何将列表
存储到数据库中,因此它失败了
您可以做的是定义一个自定义的ValueConverter
,它指示EF Core如何将特定属性存储到数据库列中(您可以查看此主题)
最好的方法可能是使用以下方法定义此转换:
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity()
.Property(p=>p.Names)
.哈斯转换(
listOfStringNames=>JsonConvert.SerializeObject(listOfStringNames),
namesJsonRepresentation=>JsonConvert.DeserializeObject(namesJsonRepresentation));
.HasData(
新MyEntity{Id=1,Names=new List{“text1”,“text2”},
新的MyEntity{Id=2,Names=new List{“text1”,“text2”,“text3”},
新MyEntity{Id=3,Names=new List{“text1”,“text2”},
新的MyEntity{Id=4,Names=new List{“text1”,“text2”},
新的MyEntity{Id=5,name=new List{“text1”、“text2”、“text3”});
}
作为旁注,我想提到的是,尽管HasData
很好,但根据我的个人经验,最好只编写我自己的DatabaseInitializer
类,该类将使用我想要的任何自定义逻辑为我需要的数据播种,而不使用任何
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" } });
}