9

코드를 먼저 사용하고 수동 마이그레이션을 통해 Entity Framework 4.3을 사용하고 있습니다. 두 개의 사용자 지정 discriminator 필드를 사용하는 TPH (table-per-hierarchy) 설치를 매핑하려고합니다. 하나는 판별 자 자체이고 다른 하나는 소프트 삭제 (NH 클래스 매핑의 "where"옵션과 유사)입니다. 정확한 설정은 EF 4.2에서 실행되는 다른 프로젝트에서도 잘 작동합니다.Entity Framework 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() 

미켈

답변

12

이 4.3과 4.3.1 알려진 문제입니다. (4.3.1에서 수정 사항을 적용하기에는 너무 늦은 것으로 나타났습니다.) 운좋게도 코드를 변경하여 작동하게하는 매우 간단한 방법이 있습니다.

간단히 말해, 4.1에서 단일 EntityConfiguration에서 연결된 맵 호출을 할 수있었습니다. 및 4.2. 이 패턴처럼 뭔가 :

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

이 4.3에서 작동하지 않는 대신 해당 개체에 대한 EntityConfiguration 각지도 통화를 할 수 있습니다. 그래서 이런 패턴 뭔가 : 그들이 필요하지 않기 때문에

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"); 
       }); 
} 

(I은 일반 매개 변수의 몇 가지를 제거했지만, 그건 당신의 구체적인 사례를 복용

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

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

이 작동합니다

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"); 
     }); 
    } 
} 
:이 같은 것을 사용하는 것이이 사용하여 명시 적 EntityConfigurations을 수행하지 않는 것이 중요합니다)

.3210

그리고는

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Configurations 
     .Add(new ParentConfiguration()) 
     .Add(new FooConfiguration()) 
     .Add(new BarConfiguration()); 
} 

우리는 5.0에서이 문제를 해결할 계획입니다.

+0

고마워요, 제가 원했던 것입니다. 그리고 이상한 방식으로, 각 하위 유형에 대한 하나의 구성이 옳은 것으로 느껴집니다. 이전 버전과의 호환성은 좋았지 만 향후 릴리스에서 수정 될 수 있기를 바랍니다. – Mihkel

+2

이것은 3 년 늦었지 만,'Map (m => m.Requires ...')은'ToTable ("테이블 이름")을 호출하기 전에 ** 작업이 완료되면 작동 할 것입니다. Entity Framework 6.1.3 btw. –