我需要重构一个实体并将它的一些属性移动到另一个具有 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 Starts
和 Instant 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 个迁移:
- 在第一次迁移中将 Instant Prop 转换为字符串 (varchar)
- 最后在第二次迁移中从类中移除字符串 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/