Соотнесите связь с базовым классом в Entity Framework - PullRequest
0 голосов
/ 12 сентября 2018

Если у меня есть классы типа

public class BaseEntity
{
    public int Id {get;set;}
    public DateTime CreatedOn {get;set;}
    public DateTime ModifiedOn {get;set;}

    public IList<ModuleHistory> History {get;set;}
}

public class FirstEntity : BaseEntity
{
    public string FirstEntityProperty {get;set;}
}

public class SecondEntity : BaseEntity
{
    public string SecondEntityProperty {get;set;}
}

public class ModuleHistory
{
    public string Field {get;set;}
    public string FromValue {get;set;}
    public string ToValue {get;set;}

    public BaseEntity Module {get;set;}
}

Я хотел бы иметь одну таблицу для FirstEntities, одну таблицу для SecondEntities и одну таблицу для ModuleHistories. ModuleHistories, я полагаю, должен иметь столбец для BaseEntityId и один для BaseEntityType (FirstEntity, SecondEntity). Моя первая попытка сработала, но вызвала создание таблицы BaseEntities. Возможно ли для EF отобразить это без таблицы для базового объекта?

1 Ответ

0 голосов
/ 13 сентября 2018

Чтобы использовать таблицу для конкретного типа, используйте MapInheritedProperties, чтобы сообщить EF, что свойства базового класса являются частью таблиц подкласса.

Для установок EntityTypeConfiguration:

public class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
  public MyEntityConfiguration()
  {
    Map(x => x.MapInheritedProperties());
    ToTable("MyEntities");
  }
}

Если вы используете modelBuilder для настройки сущностей, тогда:

modelBuilder.Entity<MyEntity>().Map(m =>
{
  m.MapInheritedProperties();
  m.ToTable("MyEntities");
}

Изменить ниже (такжеВ отредактированном примере выше, MapInheritiedProperties должен предшествовать ToTable)

Если вы хотите дочерние отношения на уровне базового класса, то вы должны структурировать модель данных как Таблица для Иерархии, а не Таблица для Бетона, так как отношения FK1 к 1 между таблицами.У ModuleHistory не может быть FK, указывающего на «либо» FirstEntity или SecondEntity.

Возможно получить EF для сопоставления этого, хотя я не уверен в том, чтобы пытаться сделать это с Code-First .. Использование конфигураций сущностей:

Учитывая структуру класса из исходного примера:

public class FirstEntityConfiguration : EntityTypeConfiguration<FirstEntity>
{
    public FirstEntityConfiguration()
    {
        Map(x => x.MapInheritedProperties());
        ToTable("FirstEntity");
        HasKey(x => x.Id);

        HasMany(x => x.History)
            .WithOptional(x => (FirstEntity)x.Module)
            .Map(x => x.MapKey("ModuleId"));
    }
}

public class SecondEntityConfiguration : SecondEntityConfiguration<SecondEntity>
{
    public SecondEntityConfiguration()
    {
        Map(x => x.MapInheritedProperties());
        ToTable("SecondEntity");
        HasKey(x => x.Id);

        HasMany(x => x.History)
            .WithOptional(x => (SecondEntity)x.Parent)
            .Map(x => x.MapKey("ModuleId"));
    }
}

public class ModuleHistoryConfiguration : EntityTypeConfiguration<ModuleHistory>
{
    public ModuleHistoryConfiguration()
    {
        ToTable("ModuleHistory");
        HasKey(x => x.Id);
    }
}

// This mapping is needed because ModuleHistory's reference to BaseEntity. EF needs to know there is a Key.
    public class BaseEntityConfiguration : EntityTypeConfiguration<BaseEntity>
    {
        public BaseEntityConfiguration()
        {
            HasKey(x => x.Id);
        }
    }

Тогда, когда вы получите FirstEntity или SecondEntity, вы получите любую историю.

У этой реализации есть несколько серьезных предостережений:

  1. Вы потеряете ограничения FK для истории модулей, поэтому база данных не обеспечит защиту для сирот (без каскадного удаления) или исправитассоциации между историей и родителем.
  2. Вы должны взять на себя ответственность за PK в ваших таблицах TpCC, чтобы избежать возможности дублирования ключей между FirstEntity и SecondEntity.Варианты здесь включают общую последовательность между таблицами или использование UniqueIdentifier (/ w NewSequentialId ())

В конечном счете, хотя вам, вероятно, будет лучше с конфигурацией Table-per-Hierarchy, если вы хотите, чтобы дочерние ссылки вбазовый класс, в противном случае разделите историю на два класса и перенесите отношения в классы реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...