Я реализовал в своей модели данных некоторое наследование по типам таблиц (в основном это тип BaseEntity со всей базовой информацией для моих элементов и тип Employer, который наследуется от элемента BaseEntity). Кажется, что все настроено правильно, и при использовании Entities (либо через ADO.net Data Services, либо через Linq to Entities) я вижу тип Employer, и все в порядке. Проблема начинается, когда я создаю новый объект Employer и пытаюсь его сохранить.
В контексте, который не является элементом .AddToEmployer (только и AddObject или AddToBaseEntity).
Если я использую AddObject("Employer", NewEmployer), я получаю сообщение об ошибке:
The EntitySet name 'DataEntities.Employer' could not be found.
Если я использую AddToBaseEntity(NewEmployer), я получаю сообщение об ошибке:
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements orstore generated values.
Пропустил ли я шаг в настройке наследования? Есть ли какой-то особый способ сохранить унаследованные объекты? Что я делаю не так? Я предполагаю, что основная проблема заключается в том, что у меня должен быть AddToEmployer, что мне нужно сделать, чтобы это было открыто? Кажется странным, что это не вариант, поскольку я вижу тип работодателя на стороне клиента и могу делать такие вещи, как:
var NewEmployer = new Employer() - что, кажется, наводит на мысль, что я вижу тип работодателя в порядке.





У вас нет работодателя, определенного как набор сущностей, как и для типа сущности. Таким образом, вам не хватает AddToEntity в объекте контекста. Всегда существует один набор сущностей для одной иерархии классов, в данном случае это набор сущностей BaseClass.
Если вы хотите получить набор сущностей «Работодатель», вы можете попробовать вручную отредактировать файл edmx и добавить новый набор сущностей «Работодатель», а затем установить тип сущности «Работодатель» как принадлежащий этому набору сущностей. Это не должно быть сложно, я делал это много раз.
Не уверен, есть ли более обычное решение.
Ну вы получаете только набор сущностей pr. базовый класс, поэтому .AddToBaseEntity - это решение как таковое.
Но похоже, что у вас есть циклическая зависимость в вашей модели, поэтому инфраструктура Entity не может определить, в каком порядке сохранять.
Убедитесь, что у вас есть внешние ключи к базовому объекту на производных объектах, и обновите модель.
Я изменил пару вещей и смог заставить это работать. Я не совсем уверен, в чем была основная проблема, но хотел опубликовать то, что я сделал, для справки.
Восстановленные таблицы: я перестроил таблицы, начиная только с столбцов ID / Key и одного столбца данных.
Удалены лишние поля с автоинкрементом: у меня был ID с автоинкрементом в BaseEntity и у работодателя. Я удалил автоматически увеличивающийся идентификатор на работодателе и только что получил столбец Employer.BaseEntityID и внешний ключ обратно в BaseEntity.BaseEntityID. (похоже, это было виновником, но у меня сложилось впечатление, что это разрешено)
К сожалению, это приводит к тому, что унаследованные классы в структуре сущности не могут иметь свойства навигации (все свойства навигации должны быть в базовой сущности), поэтому наследование окажется непригодным для наших нужд.
Меня зовут Фани, я работаю в группе служб данных ADO.NET.
Методы ResolveName и ResolveType призваны помочь вам настроить информацию о типе, которую клиент записывает в полезную нагрузку, отправляемую на сервер, и способ материализации полезной нагрузки ответа от сервера.
Они помогают вам определять типы на клиенте и полезны во многих сценариях. Вот несколько примеров:
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();
Однако, когда клиент сериализует эту полезную нагрузку, он вставляет «Сотрудник» в качестве имени типа. что не то, что ожидается на сервере. Следовательно, вы должны предоставить преобразователь имен на клиенте,
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);
}
Спустя два года, но в интересах сохранения актуальности для поискового трафика, я быстро обошел этот способ в удобном классе, который мы использовали для быстрого заполнения нашей базы данных промежуточными данными.
Не уверен в более ранних версиях, но Entity Framework 4 позволяет вам выгружать объект в контекст как базовый объект, а затем платформа определяет ссылки на стороне сервера. Таким образом, вы не использовали бы AddToInheritedObjects () (который в любом случае устарел), а скорее метод ObjectSet <>. Add ().
Вот пример вспомогательного класса:
public ContextHelper
{
…
_context = ModelEntities();
public T Create<T>() where T : class
{
// Create a new context
_context = new ModelEntities();
// Create the object using the context (can create outside of context too, FYI)
T obj = _context.CreateObject<T>();
// Somewhat kludgy workaround for determining if the object is
// inherited from the base object or not, and adding it to the context's
// object list appropriately.
if (obj is BaseObject)
{
_context.AddObject("BaseObjects", obj);
}
else
{
ObjectSet<T> set = _context.CreateObjectSet<T>();
set.AddObject(obj);
}
return obj;
}
…
}
Таким образом, если у вас есть следующее:
class ObjectOne : BaseObject {}
class ObjectTwo {}
Вы можете легко добавить сущности в контекст:
ContextHelper ch = ContextHelper()
ObjectOne inherited = ch.Create<ObjectOne>();
ObjectTwo toplevel = ch.Create<ObjectTwo>();
…
Помня, конечно, что ContextHelper должен иметь общедоступный метод Save (), который вызывает _context.SaveChanges () - или что у вас должен быть другой способ передачи изменений объекта в хранилище данных.
Возможно, это не будет прямым ответом на любой заданный вопрос о наследовании, но, надеюсь, даст людям отправную точку для ответа на конкретные вопросы.
В качестве примечания, которое я забыл упомянуть, реализация IDisposable делает это действительно приятным.