9

我使用實體框架4.3,其中包含代碼優先和手動遷移。我試圖映射一個使用兩個自定義鑑別器字段的TPH(按層次結構)設置。一個用於鑑別器本身,另一個用於軟刪除(很像NH類映射中的「where」選項)。在EF 4.2上運行的另一個項目中,完全相同的設置工作得很好。實體框架4.3 - TPH映射和遷移錯誤

嘗試在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() 

Mihkel

回答

12

這是一個已知的問題,4.3和4.3.1。 (我們發現現在修復4.3.1太遲了。)幸運的是,有一種非常簡單的方法可以改變你的代碼,使其工作。

簡而言之,您曾經能夠在4.1中的單個EntityConfiguration上進行鏈接地圖調用。和4.2。事情是這樣的模式:

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

這並不4.3工作,相反,你必須作出該實體的EntityConfiguration每個地圖調用。因此,一個模式是這樣的:

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中解決這個問題。

+0

謝謝,這只是我想要的。以一種奇怪的方式感覺是正確的 - 更明確 - 每種亞型的配置。雖然向後兼容性會很好,但我希望在未來的版本中可以解決這個問題。 – Mihkel 2012-03-05 13:33:35

+2

這是遲了3年,但調用'Map(m => m.Requires ...'只有在**調用ToTable(「table name」)前完成**)。實體框架6.1.3順便說一句。 – 2015-06-24 07:09:57