Многоуровневое наследование Entity Framework с TPH

Я работаю с устаревшей системой, которая реализует TPH для определенного количества предметов. Таким образом, текущая структура выглядит следующим образом

 Abstract Class 1     Abstract Class 2     Abstract Class 3
         |                    |                    |
     ---------            ---------            ---------
    |    |    |          |    |    |          |    |    |
    T1   T2   T3        T4    T5   T6         T7   T8   T9

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

          --------------- Base Abstract 1 ---------- 
         |                    |                    |
 Abstract Class 1     Abstract Class 2     Abstract Class 3
         |                    |                    |
     ---------            ---------            ---------
    |    |    |          |    |    |          |    |    |
    T1   T2   T3        T4    T5   T6         T7   T8   T9

По сути, у нас есть TPT, где каждая таблица для каждого типа является TPH. Для примера из реального мира, вот что нам нужно.

          ---------------  Vehicle   --------------- 
         |                    |                    |
        Car                 Boat                 Plane
         |                    |                    |
     ---------            ---------            ---------
    |    |    |          |    |    |          |    |    |
   BMW Toyota Fiat      T4   T5   T6         T7    T8   T9

Очевидно, что есть некоторые недостатки дизайна с первоначальным дизайном, и никто не ожидал, что потребуется собрать список всех транспортных средств, не запрашивая 3 разных таблицы. Таким образом, мой вопрос в том, чтобы с существующей структурой был способ добавить эту новую иерархию в структуру сущности. Я думал что-то вроде этого

  Vehicle
  -------
  VehicleId
  TypeId (Boat, Plane, Car, etc)
  ItemFK (BoatID, PlaneId, CarId)

Это возможно? Есть ли способ сопоставить их в рамках сущности? Я не могу соответствовать им правильно. Кажется, это могло бы сработать, если бы мы заменили BoatId, PlaneId и CarId на VehicleId (например, Conditional Mapping в Entity Framework - ИЛИ операция с TPH), но в этот момент мы будем делать действительно инвазивное изменение схемы, которое на самом деле не является вариант, и я не уверен, что будет работать. По сути, мне нужен способ отобразить существующие ключи в новую иерархию. Любая помощь с благодарностью. Я в растерянности и не могу найти решение, которое отвечает на мой вопрос.

3 ответа

Вы могли бы использовать эту структуру

введите описание изображения здесь

 public class Vehicle
    {
        [Key]
        public int Id { set; get; }

        ///
        // common properties
        ///

        public Car Car { set; get; }
        public Boat Boat { set; get; }
        public Plane Plane { set; get; }
    }

    public class Car
    {
        [Key, ForeignKey("Vehicle")]
        public int VehicleId { set; get; }
        public Vehicle Vehicle { set; get; }

        ///
        // Car properties
        ///
    }

    public class Boat
    {
        [Key, ForeignKey("Vehicle")]
        public int VehicleId { set; get; }
        public Vehicle Vehicle { set; get; }

        ///
        // Boat properties
        ///
    }

    public class Plane
    {
        [Key, ForeignKey("Vehicle")]
        public int VehicleId { set; get; }
        public Vehicle Vehicle { set; get; }

        ///
        // Plane properties
        ///
    }

Проблема заключается в том, что все эти элементы на самом деле имеют небольшую общность, но невозможно собрать все эти элементы в коллекцию.

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

Соглашения TPH/TPC могут быть определены на основе DbSet<> что вы определяете в своем DbContext, Например, вместо объявления DbSet<> по производному типу TВы только заявляете DbSet<> для каждого абстрактного типа. Затем вы можете запросить абстрактные классы индивидуально с соответствующими им DbSet<> или все абстрактные классы с DbSet<> базового абстрактного типа.

В базовом абстрактном классе должно быть определено хотя бы одно поле, поэтому в ходе миграции кода будет сгенерирована таблица для типа. Наиболее логичным полем для определения будет PK. Однако миграция текущих данных не будет работать из-за коллизий PK между абстрактными классами (как вы указали в комментарии).

Другая возможность состоит в том, что Entity Framework будет правильно запрашивать все абстрактные типы, когда вы запрашиваете DbSet<> базового абстрактного типа, даже если в базе данных нет таблицы для базового абстрактного типа (поскольку базовый абстрактный тип не имеет определенных полей). Однако я не сталкивался с этим сценарием раньше, поэтому не могу с уверенностью сказать, сработает он или нет.

Другие вопросы по тегам