实体框架4.3 - TPH映射和迁移错误

Mih*_*kel 9 .net c# entity-framework database-migration entity-framework-4.3

我正在使用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());
}
Run Code Online (Sandbox Code Playgroud)

错误:

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()
Run Code Online (Sandbox Code Playgroud)

Mihkel

Art*_*ers 12

这是4.3和4.3.1的已知问题.(我们发现将修复程序放在4.3.1中为时已晚.)幸运的是,有一种相当简单的方法来更改代码,使其工作.

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

modelBuilder.Entity<Parent>()
    .Map<Foo>(...)
    .Map<Bar>(...);
Run Code Online (Sandbox Code Playgroud)

这在4.3中不起作用,而是必须在该实体的EntityConfiguration上进行每个Map调用.所以这样的模式:

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

modelBuilder.Entity<Bar>()
   .Map<Bar>(...);
Run Code Online (Sandbox Code Playgroud)

具体说明你的情况,这应该工作:

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");
                });
}
Run Code Online (Sandbox Code Playgroud)

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

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

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");
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

然后

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations
        .Add(new ParentConfiguration())
        .Add(new FooConfiguration())
        .Add(new BarConfiguration());
}
Run Code Online (Sandbox Code Playgroud)

我们打算在5.0中解决这个问题.

  • 这已经晚了3年,但调用`Map(m => m.Requires ...`只有在完成后才能工作**之前**调用`ToTable("表名")`.我在实体上框架6.1.3 btw. (2认同)