Entity Framework 4.3 - ошибка отображения и миграции TPH

Я использую Entity Framework 4.3 с первой миграцией кода и ручной миграцией. Я пытаюсь сопоставить настройку TPH (таблица на иерархию), которая использует два настраиваемых поля дискриминатора. Один для самого дискриминатора, а другой для обратимого удаления (очень похоже на параметр «где» в сопоставлениях классов NH). Точно такая же настройка прекрасно работает в другом проекте, работающем на EF 4.2.

Я получаю сообщение об ошибке при попытке добавить миграцию с помощью команды "add-migration" в консоли NuGet. Я пробовал все комбинации определения имени таблицы — атрибутов в классе, в методе «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()

Михкель


person Mihkel    schedule 29.02.2012    source источник


Ответы (1)


Это известная проблема с 4.3 и 4.3.1. (Мы обнаружили, что слишком поздно вносить исправление в 4.3.1.) К счастью, есть довольно простой способ изменить ваш код, который должен заставить его работать.

Короче говоря, в 4.1 вы могли делать связанные вызовы карты для одной EntityConfiguration. и 4.2. Что-то вроде этого шаблона:

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

Это не работает в 4.3, и вместо этого вы должны делать каждый вызов Map для 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.

person Arthur Vickers    schedule 03.03.2012
comment
Спасибо, это именно то, что я хотел. И странным образом кажется правильным - более явным - одна конфигурация для каждого подтипа. Хотя обратная совместимость была бы неплохо, и я надеюсь, что это будет исправлено в будущих выпусках. - person Mihkel; 05.03.2012
comment
Это с опозданием на 3 года, но вызовы Map(m => m.Requires... будут работать только в том случае, если это будет сделано ДО вызовов ToTable("table name"). Я на Entity Framework 6.1.3 кстати. - person Rosdi Kasim; 24.06.2015