4

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

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

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

Название EntitySet «DataEntities.Employer» не может быть найден.

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

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

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

var NewEmployer = new Employer() - что, по-видимому, свидетельствует о том, что я хорошо вижу тип Работодателя.

ответ

2

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

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

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

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

1

У вас нет Работодателя, определенного как совокупность объектов, так же как тип сущности. Таким образом, вы не используете AddToEntity в объекте context. Для одной иерархии классов всегда существует одна сущность, в этом случае она является базовым объектом BaseClass.

Если вы хотите получить набор объектов «Работодатель», вы можете попробовать вручную отредактировать файл edmx и добавить новый набор объектов «Работодатель», а затем установить тип сущности «Работодатель», принадлежащий к этому объекту. Это не должно быть сложно, я делал это много раз.

Я не уверен, есть ли еще более регулярное решение.

2

Ну, вы получаете только объект, установленный пр. базовый класс, поэтому .AddToBaseEntity - это решение как таковое.

Но похоже, что у вас есть круговая зависимость в вашей модели, так что структура Entity не может понять, в каком порядке сохранить.

Убедитесь, что у вас есть внешние ключи к основанию на ваших производных объектах и ​​обновите свою модель.

7

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

Методы и помогут вам настроить информацию о типе, которую клиент пишет в полезной нагрузке, отправленной на сервер, и о том, как материально-полезная нагрузка от сервера.

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

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

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

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

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

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

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

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); 
} 
1

Подойдя два года спустя, но в интересах сохранения его значение для поискового трафика, вот так, как я работал вокруг этого быстро в классе удобства, которые мы использовали, чтобы быстро заполнить нашу базу данных с данными промежуточных ,

Не уверен в более ранних версиях, но 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() - или тот у вас должен быть какой-то другой способ изменения объектов до хранилища данных.

Это может быть не прямой ответ на любой вопрос о наследовании, но, надеюсь, дает людям отправную точку для ответа на специфику.

+0

В качестве примечания, которое я забыл упомянуть, реализация IDisposable делает это очень приятным. – JohnMetta 2010-12-23 20:16:39

Смежные вопросы