簡體   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