Entity Framework 4.3 - TPH 映射和迁移错误

Posted

技术标签:

【中文标题】Entity Framework 4.3 - TPH 映射和迁移错误【英文标题】:Entity Framework 4.3 - TPH mapping and migration error 【发布时间】:2012-03-18 23:21:28 【问题描述】:

我正在使用 Entity Framework 4.3 代码优先和手动迁移。我正在尝试映射使用两个自定义鉴别器字段的 TPH(每层次结构表)设置。一个用于鉴别器本身,另一个用于软删除(很像 NH 类映射中的“where”选项)。完全相同的设置在另一个在 EF 4.2 上运行的项目中运行良好。

尝试使用 NuGet 控制台中的“add-migration”命令添加迁移时出现错误。我已经尝试了定义表名的所有组合 - 类上的属性、“OnModelCreating”方法、EntityTypeConfiguration 类等。我以前不涉及复杂层次映射的迁移工作得很好。

我偶然发现了 EF 4.3 中的一些重大变化吗?

代码:

//---- Domain classes ---------------------

public abstract class ParentClass

    public string ParentString  get; set; 


public class Foo : ParentClass

    public string FooString  get; set; 


public class Bar : ParentClass

    public string BarString  get; set; 


//---- Mapping configuration --------------

public class ParentConfiguration : EntityTypeConfiguration<ParentClass>

    public ParentConfiguration()
    
        Map<Foo>(m =>
        
            m.Requires("IsActive").HasValue(1);
            m.Requires("Type").HasValue("Foo");
        )
        .ToTable("Parent");

        Map<Bar>(m =>
        
            m.Requires("IsActive").HasValue(1);
            m.Requires("Type").HasValue("Bar");
        )
        .ToTable("Parent");
    


//---- Context ----------------------------

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    modelBuilder.Configurations.Add(new ParentConfiguration());

错误:

System.InvalidOperationException: The type 'Foo' has already been mapped to table 'Parent'. Specify all mapping aspects of a table in a single Map call.
   at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.AddMappingConfiguration(EntityMappingConfiguration mappingConfiguration)
   at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ReassignSubtypeMappings()
   at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
   at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
   at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
   at System.Data.Entity.Migrations.Extensions.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
   at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(Action`1 writeXml)
   at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(DbContext context)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.GetMigrator()
   at System.Data.Entity.Migrations.Design.ToolingFacade.GetPendingMigrationsRunner.RunCore()
   at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()

米克尔

【问题讨论】:

【参考方案1】:

这是 4.3 和 4.3.1 的一个已知问题。 (我们发现将修复程序放入 4.3.1 为时已晚。)幸运的是,有一种相当简单的方法可以更改您的代码以使其正常工作。

简而言之,您曾经能够在 4.1 中对单个 EntityConfiguration 进行链式地图调用。和 4.2。像这样的模式:

modelBuilder.Entity<Parent>()
    .Map<Foo>(...)
    .Map<Bar>(...);

这在 4.3 中不起作用,相反,您必须在该实体的 EntityConfiguration 上进行每个 Map 调用。所以像这样的模式:

modelBuilder.Entity<Foo>()
   .Map<Foo>(...);

modelBuilder.Entity<Bar>()
   .Map<Bar>(...);

具体来说,这应该可行:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    modelBuilder.Entity<ParentClass>()
        .ToTable("Parent");

    modelBuilder.Entity<Foo>()
        .Map(m =>
                
                    m.Requires("IsActive").HasValue(1);
                    m.Requires("Type").HasValue("Foo");
                );

    modelBuilder.Entity<Bar>()
        .Map(m =>
                
                    m.Requires("IsActive").HasValue(1);
                    m.Requires("Type").HasValue("Bar");
                );

(我删除了一些通用参数,因为它们不是必需的,但这并不重要。)

使用显式 EntityConfigurations 执行此操作,您将使用如下内容:

public class ParentConfiguration : EntityTypeConfiguration<ParentClass>

    public ParentConfiguration()
    
        ToTable("Parent");
    


public class FooConfiguration : EntityTypeConfiguration<Foo>

    public FooConfiguration()
    
        Map(m =>
        
            m.Requires("IsActive").HasValue(1);
            m.Requires("Type").HasValue("Foo");
        );
    


public class BarConfiguration : EntityTypeConfiguration<Bar>

    public BarConfiguration()
    
        Map(m =>
        
            m.Requires("IsActive").HasValue(1);
            m.Requires("Type").HasValue("Bar");
        );
    

然后

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    modelBuilder.Configurations
        .Add(new ParentConfiguration())
        .Add(new FooConfiguration())
        .Add(new BarConfiguration());

我们计划在 5.0 中解决此问题。

【讨论】:

谢谢,这正是我想要的。并且以一种奇怪的方式感觉正确 - 更明确 - 每个子类型都有一个配置。虽然向后兼容性会很好,但我希望这在未来的版本中得到修复。 这已经晚了 3 年,但只有在 之前 调用 ToTable("table name") 之后才能调用 Map(m =&gt; m.Requires...。我在实体框架 6.1.3 顺便说一句。

以上是关于Entity Framework 4.3 - TPH 映射和迁移错误的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework 4.3 多应用数据库迁移策略

在 Entity Framework 4.3 中增量播种数据的最佳方法

将 SQL Server Compact 4.0.0.1 与 Entity Framework 4.3 一起使用

使用 Entity Framework Migrations 4.3 时如何显式命名数据库

Entity Framework Core 性能优化

Entity Framework Core 性能优化