Entity Framework Многоуровневое наследование с TPH
Я работаю с устаревшей системой, которая реализует TPH для определенного количества элементов. Итак, текущая структура выглядит так:
Abstract Class 1 Abstract Class 2 Abstract Class 3
| | |
--------- --------- ---------
| | | | | | | | |
T1 T2 T3 T4 T5 T6 T7 T8 T9
Таким образом, Type (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
Очевидно, что есть некоторые недостатки дизайна с первоначальным дизайном, и никто не ожидал, что должен захватить список всех автомобилей без запроса трех разных таблиц. Поэтому мой вопрос заключается в том, что с существующей структурой есть способ добавить эту новую иерархию в структуру сущности. Я думал что-то вроде этого
Vehicle
-------
VehicleId
TypeId (Boat, Plane, Car, etc)
ItemFK (BoatID, PlaneId, CarId)
Возможно ли это? Есть ли способ сопоставить их в структуре сущностей? Кажется, я не могу их правильно подобрать. Кажется, что это могло бы работать, если бы мы заменили BoatId, PlaneId и CarId с помощью VehicleId (например Условное сопоставление в платформе Entity Framework - ИЛИ с помощью TPH), но в этот момент мы бы сделали действительно инвазивное изменение схемы, которое на самом деле не вариант, и я не уверен, что это даже сработает. По сути, мне нужен способ сопоставления существующих ключей с новой иерархией. Любая помощь приветствуется. Я в недоумении и не могу найти решения, которое отвечает на мой вопрос.
Ответы
Ответ 1
Вы можете использовать эту структуру
![введите описание изображения здесь]()
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
///
}
Ответ 2
Проблема состоит в том, что все эти элементы фактически разделяют небольшую общность, но нет способа собрать все эти элементы в коллекцию.
Возможно, у вас могут быть типы в каждой иерархии, реализующие общий интерфейс? Поскольку каждая иерархия уже является отдельной таблицей, похоже, что вы не получите многого - и кажется, что это не стоило бы хлопот - добавив общий базовый класс.
Ответ 3
Соглашения TPH/TPC могут быть определены на основе DbSet<>
, которые вы определяете в своем DbContext
. Например, вместо объявления DbSet<>
для производного типа T
вы объявляете только DbSet<>
для каждого абстрактного типа. Затем вы можете запросить абстрактные классы отдельно с соответствующими DbSet<>
или всеми абстрактными классами с DbSet<>
базового абстрактного типа.
В базовом абстрактном классе должно быть задано хотя бы одно поле, поэтому Code-First Migrations будет генерировать таблицу для типа. Наиболее логичным полем для определения будет ПК. Однако миграция текущих данных не будет работать из-за столкновений PK между абстрактными классами (как вы указали в комментарии).
Другая возможность заключается в том, что Entity Framework будет корректно запрашивать все абстрактные типы при запросе DbSet<>
базового абстрактного типа, даже если в базе данных нет базового абстрактного типа (поскольку базовый абстрактный тип не имеет поля определены). Тем не менее, я не сталкивался с этим сценарием раньше, поэтому не могу с уверенностью сказать, будет ли это работать или нет.