Мне удалось решить эту проблему, хотя я не совсем доволен решением. В итоге я написал хранимые процедуры для сопоставления операций вставки, обновления и удаления для 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. Таким образом, по крайней мере, я могу сохранить все изменения в производных типах сущностей, даже если это означает, что эти изменения включают добавление бессмысленных столбцов, которые всегда будут нулевыми в физическом хранилище.