Вопрос

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

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

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

Не удалось найти имя набора объектов "DataEntities.Работодатель".

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

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

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

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

Это было полезно?

Решение 3

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

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

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

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

Другие советы

Меня зовут Фани, и я работаю в команде ADO.NET Data Services.

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

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

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

Когда вы используете клиент для работы с экземплярами типа объекта 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);
}

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top