Как я могу добавить наследование к объекту, определенному в EntityDataModel (EF 4)? - PullRequest
0 голосов
/ 24 сентября 2010

У меня есть простое наследование 2 объектов, определенное в модели EF, Person <- User. </p>

Person - это базовая сущность / класс, она не абстрактна и содержит поля, такие как имя, фамилия, адрес электронной почты.

Пользователь является производным объектом / классом и содержит поля, такие как имя пользователя, lastlogin, islockedout.

База данных использует схему типа «таблица для каждого типа», поэтому есть 1 таблица для Person и другая таблица для User. Оба используют одно поле первичного ключа, PersonID. PersonID - это столбец IDENTITY, но в EDM для StoreGeneratedPattern for PersonID задано значение Нет.

Поскольку это ошибка типа наследования таблицы для типа, может существовать строка / объект Person, для которого нет соответствующей строки / объекта User. Это сделано для того, чтобы система могла содержать данные о людях, которые не являются пользователями. Тем не менее, Человек может в конечном итоге стать Пользователем, и именно здесь у меня возникают проблемы.

У меня есть тестовый пример для этого сценария, где система находит Лица, которого она хочет превратить в Пользователя. Я попытался установить поле PersonID для нового объекта User, добавить его в ObjectContext и сохранить изменения. В результате база данных создает новую строку Person вместе с новой строкой User, игнорируя значение, заданное для PersonID.

Как я могу обойти это? Нужно ли создавать sprocs для обработки операций EDM crud?

Ответы [ 2 ]

2 голосов
/ 24 сентября 2010

Вот ваша проблема:

У меня есть тестовый пример для этого сценария, где система находит человека, которого она хочет превратить в пользователя

Объектыне может изменить типы, в C # или любой другой OOPL на основе классов, о которых я знаю.EF не меняет это.

Вам нужно изменить свой дизайн.Это не ОО.Я писал об этом в прошлом году:

Одним из ментальных барьеров, которые вы должны преодолеть при разработке хорошего объектно-реляционного отображения, является тенденция мыслить в первую очередь в объектно-ориентированных терминах.или реляционные термины, в зависимости от вашей личности.Хорошее объектное реляционное отображение, тем не менее, включает в себя как хорошую объектную модель, так и хорошую реляционную модель.Например, предположим, у вас есть база данных с таблицей для сотрудников и связанными таблицами для сотрудников и клиентов.Один человек может иметь запись во всех трех таблицах.Теперь, с строго реляционной точки зрения, вы можете создать базу данных VIEW для сотрудников и другую для клиентов, которые содержат информацию из таблицы People.При использовании одного или другого ПРОСМОТРА вы можете временно думать об отдельном человеке как о «просто» сотруднике или «просто» клиенте, даже если вы знаете, что они оба.Таким образом, у кого-то из этого мировоззрения может возникнуть соблазн сделать OO-отображение, где Employee и Customer являются (прямыми) подклассами Person.Но это не работает с данными, которые у нас есть;поскольку у одного лица есть записи как о сотруднике, так и о клиенте (и поскольку ни один экземпляр Person не может одновременно иметь конкретный подтип Employee и Customer), отношение OO между Person и Employee должно быть состав , а не наследованием, ианалогично для человека и клиента.

0 голосов
/ 25 сентября 2010

Мне удалось решить эту проблему, хотя я не совсем доволен решением. В итоге я написал хранимые процедуры для сопоставления операций вставки, обновления и удаления для Person и User (поскольку они находятся в одном наборе сущностей, обе должны быть сопоставлены всеми тремя sprocs). Sproc вставки для пользователя принимает параметр PersonID и использует его, чтобы решить, создавать ли новую строку Person или присоединять к существующей строке Person.

Подвох заключается в том, что PersonID должен отображаться как входной параметр sproc и как привязка столбца результата. Когда БД должен сгенерировать новый PersonID, мы должны вернуть его обратно, используя привязку результата, чтобы другие таблицы получили правильное значение для столбцов внешнего ключа, ссылающихся на PersonID. Кроме .... вы не можете сопоставить User.PersonID как входной параметр и привязку столбца результата одновременно. Это вызывает исключительную ситуацию во время выполнения: «Невозможно определить действительный порядок для зависимых операций. Зависимости могут существовать из-за ограничений внешнего ключа, требований модели или сохранения сгенерированных значений».

Я закончил тем, что добавил в таблицу User (и в соответствующую концептуальную модель) новый столбец, который является обнуляемым int (я назвал его BasePK). В EDM я защитил методы получения и установки этого свойства, чтобы скрыть их от открытого интерфейса. Затем я сопоставил BasePK как входной параметр sproc и сопоставил PersonID как привязку столбца результата, чтобы получить значение идентификатора, если оно было сгенерировано. Одна перегрузка для конструктора User выглядит следующим образом:

публичный пользователь (int personID): base () { this.BasePK = personID; }

Так что теперь, когда я хочу превратить существующего Человека в Пользователя, мне просто нужно создать пользователя с использованием этой перегрузки.

int personID = [некоторый метод для поиска человека и возврата его / ее PersonID]; var User = новый пользователь (personID);

Когда ObjectContext идет для вставки сущности, он передает PersonID в sproc через свойство BasePK. Когда sproc завершен, он возвращает PersonID к фактическому свойству первичного ключа.

Мне не понравилась идея добавления столбца и свойства для достижения этой цели, но она сочетается с моим комментарием к ответу Крейга: я хочу иметь возможность подключаться к Person с новыми специализациями без необходимости менять / каждый раз перекомпоновывать сущность Person. Таким образом, по крайней мере, я могу сохранить все изменения в производных типах сущностей, даже если это означает, что эти изменения включают добавление бессмысленных столбцов, которые всегда будут нулевыми в физическом хранилище.

...