Невозможно сохранить унаследованные типы Entity Framework

.net entity-framework inheritance savechanges table-per-type

Вопрос

В моей модели данных реализовано наследование таблиц для каждого типа (в основном у BaseEntity тип BaseEntity со всей базовой информацией для моих элементов и тип Employer который наследуется от элемента BaseEntity ). Кажется, все настроено правильно, и при использовании сущностей (либо через ADO.net Data Services, либо через Linq to Entities) я вижу тип Employer и все выглядит нормально. Проблема начинается, когда я создаю новый объект Employer и пытаюсь сохранить его.

В контексте, который не является элементом .AddToEmployer (только и AddObject или AddToBaseEntity ).

Если я использую AddObject("Employer", NewEmployer) я получаю сообщение об ошибке:

Имя EntitySet 'DataEntities.Employer' не найдено.

Если я использую AddToBaseEntity(NewEmployer) я получаю сообщение об ошибке:

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

Я пропустил шаг в настройке наследства? Есть ли какой-то конкретный способ сохранить объекты, которые наследуются? Что я делаю неправильно? Я предполагаю, что основная проблема заключается в том, что у меня должен быть AddToEmployer , что мне нужно сделать, чтобы разоблачить это? Кажется странным, что это не вариант, так как я вижу тип Employer на стороне клиента и могу делать такие вещи, как:

var NewEmployer = new Employer() - что, по-видимому, говорит о том, что я хорошо вижу тип Employer.

Принятый ответ

Я изменил пару вещей и смог заставить это работать. Я не совсем уверен, что было основной проблемой, но хотел опубликовать то, что я сделал для справки.

Перестроенные таблицы: я перестроил таблицы, начиная только со столбцов ID / Key и одного столбца данных.

Удалены дополнительные автоинкрементные поля: у меня был автоматически инкрементный идентификатор на BaseEntity и на работодателе. Я удалил автоинкрементный идентификатор на работодателе и только что имел столбец Employer.BaseEntityID и внешний ключ обратно к BaseEntity.BaseEntityID. (кажется, это был виновник, но у меня сложилось впечатление, что это разрешено)

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


Популярные ответы

Меня зовут Фани, и я работаю в команде служб данных ADO.NET.

ResolveName и ResolveType помогут вам настроить информацию о типе, которую клиент записывает в полезную нагрузку, отправляемую на сервер, и способ материализации ответной полезной нагрузки с сервера.

Они помогают вам разрешать типы на клиенте и полезны во многих сценариях. Вот несколько примеров:

  1. Иерархия типов объектов на клиенте отличается от серверной.
  2. Типы сущностей, предоставляемые службой, участвуют в наследовании, и вы хотите работать с производными типами на клиенте.

ResolveName используется для изменения имени объекта, который мы помещаем в провод при ResolveName запроса на сервер.

Рассмотрим эту модель данных: на сервере

public class Employee {
    public int EmployeeID {get;set;}
    public string EmployeeName {get;set;}
}

public class Manager:Employee {
    public List<int> employeesWhoReportToMe {get;set;}
}

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

context.AddObject("Employees",ManagerInstance ); <-- add manager instance to the employees set.
context.SaveChanges();

Однако, когда клиент сериализует эту полезную нагрузку, он вводит «Employee» в качестве имени типа, которое не соответствует ожидаемому на сервере. Следовательно, вы должны предоставить имя клиента на клиенте,

context.ResolveName = delegate(Type entityType){
    //do what you have to do to resolve the type to the right type of the entity on the server
    return entityType.FullName;
}

распознаватель типов используется таким же образом.

context.ResolveType = delegate(string entitySetName){
    //do what you have to do to convert the entitysetName to a type that the client understands
    return Type.GetType(entitySetName);
}


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow