EF4 CTP5, сопоставление разных сущностей с одной (существующей) таблицей

Используя подход «сначала код» (но с существующей схемой базы данных), мы пытаемся сопоставить 2 разных объекта (клиент и ресурс) с одной и той же таблицей. Обе сущности имеют одинаковые ключи и сопоставление.

Однако при запуске приложения у нас возникает ошибка времени выполнения, сообщающая нам это загадочное сообщение:

System.InvalidOperationException: Type 'Resource' cannot be mapped to table 'CLIENT' since type 'Customer' also maps to the same table and their primary key names don't match. Change either of the primary key property names so that they match.    

Пример:

 public class EntityA
{
    public string ID { get; set; }
    public string Discriminator { get; set; }
    public string TimeStamp { get; set; }
}
public class EntityB
{
    public string ID { get; set; }
    public string Discriminator { get; set; }
    public string CreatedBy { get; set; }
}
public class EntityAConfiguration : EntityTypeConfiguration<EntityA>
{
    public EntityAConfiguration()
    {
        HasKey(x => new {x.ID, x.Discriminator } );
        Property(x => x.ID).HasColumnName("MyTable_ID").HasDatabaseGenerationOption(DatabaseGenerationOption.None);
        Property(x => x.Discriminator).HasColumnName("MyTable_Discriminator").HasDatabaseGenerationOption(DatabaseGenerationOption.None);            
        Property(x => x.TimeStamp).HasColumnName("MyTable_TimeStamp");
        ToTable("MyTable");
    }
}
public class EntityBConfiguration : EntityTypeConfiguration<EntityB>
{
    public EntityBConfiguration()
    {
        HasKey(x => new { x.ID, x.Discriminator });
        Property(x => x.ID).HasColumnName("MyTable_ID").HasDatabaseGenerationOption(DatabaseGenerationOption.None);
        Property(x => x.Discriminator).HasColumnName("MyTable_Discriminator").HasDatabaseGenerationOption(DatabaseGenerationOption.None);
        Property(x => x.CreatedBy).HasColumnName("MyTable_CreatedBy");
        ToTable("MyTable");
    }
}

Приведенный выше код похож на наш код клиента/ресурса (но проще для объяснения!). Однако получите то же сообщение об ошибке, в котором говорится, что EntityA и EntityB не могут быть сопоставлены с одной и той же таблицей, поскольку имена их первичных ключей не совпадают.

Есть идеи, что не так с нашим отображением? Любая идея, как мы можем использовать разные объекты в одной таблице?

Спасибо за вашу помощь


person Mathieu Hétu    schedule 15.01.2011    source источник


Ответы (1)


Для сопоставления двух объектов с одной таблицей необходимо создать сложный тип или Table Per Hierarchy (TPH). Вы не можете просто сопоставить 2 объекта с одной таблицей, как это. Дайте мне знать, какой из них лучше описывает вашу модель предметной области, и я предоставлю вам необходимую объектную модель/свободный код API.

Обновление: отображение TPH:

public abstract class EntityBase
{
    [Column(Name = "MyTable_ID")]  
    public string ID { get; set; }
    [Column(Name = "MyTable_Discriminator")]  
    public string Discriminator { get; set; }      
}
public class EntityA : EntityBase
{
    [Column(Name = "MyTable_TimeStamp")]
    public string TimeStamp { get; set; }
}
public class EntityB : EntityBase
{
    [Column(Name = "MyTable_CreatedBy")]
    public string CreatedBy { get; set; }
}                
public class StackoverflowTestContext : DbContext
{
    public DbSet<EntityBase> Entities { get; set; }        
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<EntityBase>()
                    .HasKey(x => new { x.ID, x.Discriminator });

        modelBuilder.Entity<EntityBase>()
                    .Map<EntityA>(m => m.Requires("TPHDiscriminator")
                    .HasValue("yourDesiredValueForA"))
                    .Map<EntityB>(m => m.Requires("TPHDiscriminator")
                    .HasValue("yourDesiredValueForB"))
                    .ToTable("MyTable");
    }
}
person Morteza Manavi    schedule 15.01.2011
comment
Похоже, что TPH может быть лучшим вариантом здесь. С TPH и дискриминатором, я думаю, мы сможем заставить наш маленький пример работать? - person Mathieu Hétu; 15.01.2011
comment
Я тоже так думал. Итак, учитывая, что TPH создаст для вас столбец «Дискриминатор», нужно ли вам по-прежнему иметь свойство Дискриминатор в ваших EntityA и EntityB? - person Morteza Manavi; 15.01.2011
comment
Нет, мы работаем над существующей схемой БД, которую мы никак не можем изменить... - person Mathieu Hétu; 15.01.2011
comment
Я обновил ответ сопоставлением TPH, посмотрите, как это работает для вас. - person Morteza Manavi; 15.01.2011
comment
Спасибо... Я пробую это в своем домене "мгновенно" :-) - person Mathieu Hétu; 15.01.2011