Как использовать общие имена столбцов в отображении таблицы на иерархию (TPH) - PullRequest
24 голосов
/ 08 декабря 2010

Вначале я использую Entity Framework 4 CTP5-код ​​и имею отображение таблицы на иерархию (TPH).Некоторые из моих классов в иерархии имеют общие свойства.

public class BaseType
{
    public int Id { get; set; }
}

public class A : BaseType
{
    public string Customer { get; set; }
    public string Order { get; set; }
}

public class B : BaseType
{
    public string Customer { get; set; }
    public string Article { get; set; }
}

public class C : BaseType
{
    public string Article { get; set; }
    public string Manufacturer { get; set; }
}

Соглашение по умолчанию сопоставляет это со следующими столбцами:

  • Id
  • Article1
  • Артикул2
  • Заказчик1
  • Заказчик2
  • Производитель
  • Заказ
  • Тип

Iхотите, чтобы EF4 разделял общие свойства, чтобы в итоге получилось следующее:

  • Id
  • Артикул
  • Клиент
  • Производитель
  • Заказ
  • Тип

Помимо уменьшенного количества столбцов, он имеет преимущество в том, что может искать записи на основе статьи, например, без необходимости знать, какие типыточно иметь свойство Article.

Я попытался сопоставить каждое общее свойство с одним и тем же столбцом:

modelBuilder.Entity<B>().Property(n => n.Article).HasColumnName("Article");
modelBuilder.Entity<C>().Property(n => n.Article).HasColumnName("Article");

, но при этом возникло следующее исключение:

Указана схемане является действительным.Ошибки: (36,6): ошибка 0019: каждое имя свойства в типе должно быть уникальным.Имя свойства Article было уже определено.

Кто-нибудь знает, как обойти это правило проверки?

Ответы [ 2 ]

18 голосов
/ 08 декабря 2010

Нет обходного пути, чтобы обойти эту проверку.В TPH столбец либо принадлежит базовому классу, который наследуется всеми дочерними, либо специализирован для дочернего класса.Вы не можете поручить EF сопоставить его с двумя вашими детьми, но не с другим.Попытка сделать это (например, поместив [Column(Name = "Customer")] в A.Customer и B.Customer) вызовет MetadataException с этим сообщением:

Указанная схема не являетсядействительный.Ошибки: (10,6): ошибка 0019: каждое имя свойства в типе должно быть уникальным.Имя свойства 'Customer' уже определено.


TPH Решение:

Одним из решений этой проблемы было бы продвижение Customer и Article свойства базового класса:

public class BaseType {
    public int Id { get; set; }
    public string Customer { get; set; }
    public string Article { get; set; }
}

public class A : BaseType {
    public string Order { get; set; }
}

public class B : BaseType { }

public class C : BaseType {
    public string Manufacturer { get; set; }
}

, что приводит к желаемой схеме:

alt text


TPT Solution (Рекомендуется):

При этом я рекомендую рассмотреть возможность использования Таблицы для каждого типа (TPT), поскольку она лучше подходит для вашего сценария:

public class BaseType
{
    public int Id { get; set; }
}

public class A : BaseType
{
    [Column(Name = "Customer")]
    public string Customer { get; set; }
    public string Order { get; set; }
}

public class B : BaseType
{
    [Column(Name = "Customer")]
    public string Customer { get; set; }

    [Column(Name = "Article")]
    public string Article { get; set; }
}

public class C : BaseType
{
    [Column(Name="Article")]
    public string Article { get; set; }
    public string Manufacturer { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<BaseType> BaseTypes { get; set; }        

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<BaseType>().ToTable("BaseType");
        modelBuilder.Entity<A>().ToTable("A");
        modelBuilder.Entity<C>().ToTable("C");
        modelBuilder.Entity<B>().ToTable("B");          
    }
}

alt text

8 голосов
/ 02 апреля 2013

Для тех, у кого возникли проблемы с этой проблемой, теперь она исправлена ​​в EF6: Структура сущностей - Codeplex

...