Entity Framework: Является ли Table Per Hierarchy подходящим шаблоном наследования для этой ситуации?
Представьте, что у меня есть иерархия объектов, которые я хочу сохранить в своем хранилище данных Entity Framework 4.1. Я создаю их, используя Code First. Они выглядят так:
BasicState
has many -> StatefulEntities
has a -> CreationDate
ReceivedState
has a -> EntityLocation
ApprovedState
has a -> EntityLocation
OrderedState
has a -> Order
DispatchedState
has a -> Order
has a -> DispatchNumber
BasicState
является родителем для всех других состояний, все остальное разделяет эти два поля / отношения.
Моя первоначальная мысль и способ, которым я это реализовал, состояла в том, чтобы использовать наследование Table Per Hierarchy, потому что казалось, что я мог просто наследовать от BasicState
и мои другие государства участвуют в этих общих свойствах.
Однако это вызвало проблему, потому что, когда разные состояния совместно используют поле, базовая модель данных не имеет, поэтому, например, моя база данных будет иметь EntityLocation_Id
от одного из ReceivedState
а также ApprovedState
а также EntityLocation_Id1
с другой. Это затрудняет создание тестовых данных, поскольку вы не знаете, какие поля принадлежат каким моделям. Я спрашивал об этом ранее.
Решение, которое я выбрал, заключалось в следующем:
public abstract class BaseState
{
public DateTime CreatedDate { get; set; }
public ICollection<StatefulEntity> StatefulEntities{get;set;}
}
public abstract class LocationState : BaseState
{
public Location EntityLocation { get; set; }
}
public class ReceivedState : LocationState
{
}
public class ApprovedState : LocationState
{
}
Это работало частично, однако, хотя он создал один EntityLocation_Id
это все еще создало два Order_Ids
за OrderedState
а также DispatchedState
даже если они ведут себя одинаково и реализации не различимы.
После того, как это почти наполовину решено, я столкнулся с другой проблемой, которая заставляет меня задать этот вопрос:
Учитывая, что я отношения между BasicState
а также StatefulEntities
много ко многим в обоих направлениях, я должен быть в состоянии найти детали заказа от OrderedStates
принадлежность к StatefulEntity
,
Проблема в том, что хотя это довольно легко представить в SQL, наследование означает, что Entity Framework не знает, является ли BasicState
является OrderedState
так что, похоже, нет никакого способа сделать одну поездку в базу данных, чтобы включить OrderedState.Order
,
Так что я не могу сделать что-то вроде этого:
statefulEntityRepository.Get().Where( x => x.Id == 1 ).Include( x => x.BasicStates ).Include( x.BasicStates.Order );
Очевидно, это не тот код, который будет работать, но он показывает, в чем проблема - Орден принадлежит только определенным подтипам BasicState
и поэтому EF не будет предварительно загружать его, даже если я использую какое-то приведение.
Если я попробую проецирование, я получу что-то вроде этого:
statefulEntityRepository.Get().Select( x=> new {
StatefulEntity = x,
EntityLocation = ( from state in x.BaseStates where state is ReceivedState select state.EntityLocation )
}
Но, получив это, мне нужно найти путь назад от анонимного типа, возвращаемого проекцией к моему StatefulEntity, чтобы остальная часть моего кода могла с этим справиться, что выглядит как значительный длинный путь.
Я дошел до попытки определить мой базовый класс и наследники таким образом:
public abstract class BaseState
{
public DateTime CreatedDate { get; set; }
public ICollection<StatefulEntity> StatefulEntities{get;set;}
public long EntitytLocationId { get; set; }
}
public abstract class LocationState : BaseState
{
[Column(name="EntityLocationId")]
public Location EntityLocation { get; set; }
}
И так далее, но потом я, кажется, нарушаю основную идею наличия TPH в первую очередь, и я чувствую, что с таким же успехом я мог бы перенести свою собственную объектную модель на общий класс данных.
Редактировать: я думаю, что у меня есть немного больше понимания этого сейчас - от попытки установить ForeignKey на дальнем конце этого отношения (то есть отношения между Location и LocationState) это выглядит так, как будто обратная коллекция в Order или Location может Не говорите о свойстве, которое отсутствует в базовом объекте, поэтому мне придется использовать версию выше. Это создает новую проблему в том, как я управляю делами, у которых нет EntityLocationId или OrderId - если я сделаю эти поля обнуляемыми, то возникает ошибка, что ссылочные поля не могут быть пустыми при создании базы данных, и по умолчанию нет способа установить начальное значение для поле в первом коде.
Кто-нибудь может порекомендовать лучший способ представления этого типа модели, которая будет работать с Entity Framework?