c# - "The type mapping for ' Instant ' has not implemented code literal generation"分割实体时

标签 c# .net-core nodatime ef-core-2.2

我需要重构一个实体并将它的一些属性移动到另一个具有 1:1 关系的实体。但是,当我创建一个新类并将大部分 Instant 类型属性移动到它时,创建 Entity1Id作为其关键加上它们之间的虚拟导航属性,当我想创建迁移时,我收到以下错误:

System.NotSupportedException: The type mapping for 'Instant' has not implemented code literal generation.

这是怎么回事?我没有播种(发现这个错误:https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/526)

我创建了一个简单的存储库来演示此行为,您可以在其中使用 .Net Core 2.2 对其进行测试。我目前在使用 Mac;我不确定它是否有任何影响。

GitHub 存储库:https://github.com/Slaviusz/EFCoreSplittingEntityProblem

编辑:

根据要求,Github 存储库的实际内容是什么,代码示例如下。请注意,我在包含数十个实体的解决方案中遇到过此问题,但我能够将其简化为与一个实体重构项目一样简单。

从一个简单的实体开始:

public class Table1
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Instant Starts { get; set; }
    public Instant Ends { get; set; }
}

public class ApplicationDbContext : DbContext
{
    ... // other code like constructors and configure method overrides
    public DbSet<Table1> Table1s { get; set; }
}

创建迁移成功后成功 dotnet ef database update . (但是根本没有必要触发它)

更多细节可以在第一次提交中看到:https://github.com/Slaviusz/EFCoreSplittingEntityProblem/commit/57562f0c978287e15d75ff1bead435501c28befc


下一步是执行重构,将两个 Instant 属性提取到辅助类,从而在它们之间创建逻辑关系。 典型的用例是将实体详细信息提取到其自己的表中,仅在需要详细信息时才需要加入/子选择。

在这种情况下 Prop Instant StartsInstant Ends移至Table2 .

public class Table1
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Table2 Table2 { get; set; }
}

public class Table2
{
    [Key] public int Table1Id { get; set; }
    public Instant Starts { get; set; }
    public Instant Ends { get; set; }
    public virtual Table1 Table1 { get; set; }
}

public class ApplicationDbContext : DbContext
{
    ... // other code like constructors and configure method overrides
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Table2>()
            .HasOne(p => p.Table1)
            .WithOne(p => p.Table2);
    }

    public DbSet<Table1> Table1s { get; set; }
    public DbSet<Table2> Table2s { get; set; }
}

都可以在第三次提交中看到:https://github.com/Slaviusz/EFCoreSplittingEntityProblem/commit/04fe59563bd510df26a37e5938889557b9741673

注意:第二次提交是我添加 .gitignore 的地方,以排除出于重现此目的而不必要的文件。

此时执行dotnet ef migrations add Split结果:

$ dotnet ef migrations add Split
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
System.NotSupportedException: The type mapping for 'Instant' 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.Migrations.Design.CSharpMigrationOperationGenerator.Generate(AddColumnOperation operation, IndentedStringBuilder builder)
   at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3[T0,T1,T2](CallSite site, T0 arg0, T1 arg1, T2 arg2)
   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)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   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 'Instant' has not implemented code literal generation.

我觉得需要注意的重要一点是,为了能够使用 EF Core In-Memory 提供程序进行测试,我使用了 2 个构造函数:

// constructor for mocking with InMemory provider
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    // return if already configured (by mocking with InMemory provider)
    if (optionsBuilder.IsConfigured)
        return;
    ... // the rest of the code to init
}

然而,这会导致 dotnet工具无法执行 cli EF Core 操作(迁移、数据库更新)。因此我有额外的类来扩展 IDesignTimeDbContextFactory<> .

public class CliDbContext : IDesignTimeDbContextFactory<ApplicationDbContext>
{
    public ApplicationDbContext CreateDbContext(string[] args)
    {
    ... // code to init in cli cases
    }
}

最佳答案

虽然在测试项目中搞砸了这个问题,但似乎只是简单地从 POCO 类中删除 Instant 属性会触发此错误。

非常粗略的解决方法是将删除拆分为 2 个迁移:

  1. 在第一次迁移中将 Instant Prop 转换为字符串 (varchar)
  2. 最后在第二次迁移中从类中移除字符串 props

两次迁移都成功了,我能够运行 dotnet ef database update 并带有关于可能的数据丢失的小警告 - 这是预期的,因为我已经编写了自定义 SQL 代码以在我创建的先前迁移中迁移数据另一个类中的新 Instant 属性。

关于c# - "The type mapping for ' Instant ' has not implemented code literal generation"分割实体时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55957249/

相关文章:

c# - 在 Windows 通用应用程序和 Azure 移动服务之间共享类

c# - EmitCalli .net 核心替代方案

c# - 如何以当前区域性格式的默认值从 Noda Time OffsetDateTime 生成 DateTimeOffset 字符串?

.net - 如何在 NodaTime 中获取 "start of the year/month"?

c# - 使用 GDI+ 重叠图像

c# - 如果我的 C# 程序中没有任何按键,如何进入登录表单?

c# - 如何使用 Visual Studio 2012 从源代码管理中分离项目?

.net - 为 .NET Core/UWP 中的单个 HTTP 请求设置自定义 WebProxy

c# - 在 .NET Core 1.1 中使用 System.IO.Ports.SerialPort

c# - 如何将 "1:15 P.M."解析为 NodaTime LocalTime?