1

Это мой первый пост здесь, поэтому я надеюсь, что все в порядке.Проблема с таблицами EF STE и Self-Referencing

вот моя проблема: У меня есть таблица в моей базе данных под названием UserTypes. Он имеет:

  1. ID;
  2. IsPrivate;
  3. Parent_ID;

Соответствующие являются первыми и третьими. У меня есть другая таблица под названием UserTypes_T, которая имеет информацию для разных типов, которая зависит от языка. Поля следующие:

  1. Language_ID;
  2. UserType_ID;
  3. Наименование;

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

Все работает нормально, пока не попытаюсь сохранить изменения в базе данных. EF сгенерировал для меня два класса объектов для этих таблиц:

Класс для пользовательских типов имеет:

  1. ID;
  2. IsPrivate;
  3. Parent_ID;
  4. Навигационное свойство для саморекламы (0..1);
  5. Навигационное свойство для дочерних элементов;
  6. Другое навигационное свойство для таблицы UserTypes_T (1 .. *);

Класс для преобразованной информации:

  1. UserType_ID;
  2. Language_ID;
  3. Наименование;
  4. Навигационное свойство таблицы UserTypes (* .. 1);
  5. Навигационное свойство таблицы языков (* .. 1);

Я получаю данные мне нужно, используя:

return context.UserTypes.Include("UserTypes_T").Where(ut => ut.IsPrivate==false).ToList(); 

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

Если я обновляю корневой элемент (Parent_ID == null), все работает! Если я обновить элемент, где PARENT_ID = NULL я получаю следующее сообщение об ошибке:

AcceptChanges cannot continue because the object’s key values conflict with another object in the ObjectStateManager.

я искал по всему интернету и читать записи в блоге от Diego B Vega (и многое другое), но моя проблема отличается. Когда я изменяю тип родительского пользователя, я фактически изменяю свойство Parent_ID, а не навигационное свойство. Я всегда стараюсь работать с идентификаторами, а не с созданными навигационными свойствами, чтобы избежать проблем.

Я сделал небольшое исследование, пытались увидеть, что объект график, который я и увидел, что там было много дублирующих организаций:

Корневой элемент был список его дочерних элементов. Каждый дочерний элемент имел обратную ссылку на корень или его родительский элемент и так далее. Ты можешь представить. Поскольку я не использовал эти навигационные свойства, потому что я использовал идентификаторы для получения/установки необходимых мне данных, я удалил их из модели. Конкретно я удалил пункты и из UserTypes класс сущности. Тогда у меня был граф объектов с каждым элементом только один раз. Я попробовал новое обновление, но у меня была такая же проблема:

Корневой элемент был обновлен отлично, но у элементов, у которых были родители, было исключение.

Я видел, что у меня было навигационное свойство в классе сущностей UserTypes_T, указывающее на тип пользователя, поэтому я тоже удалил его. Затем эта ошибка исчезла. Все элементы в графе объектов были уникальными. Но проблема осталась - я мог бы обновить свой корневой элемент без проблем, но при попытке обновления детей (без исключений) я получил нулевое ссылочное исключение в созданном классе Model.Context.Extensions:

if (!context.ObjectStateManager.TryGetObjectStateEntry(entityInSet.Item2, out entry)) 
{ 
    context.AddObject(entityInSet.Item1, entityInSet.Item2);//here! 
} 

Я попытался обновить только имя (которое находится в UserTypes_T), но ошибка совпадает.

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

PS:

Единственный способ мне удалось обновить дочерний объект использует следующий код для извлечения данных:

var userTypes = argoContext.UserTypes.Include("UserTypes_T").Where(ut => ut.IsPrivate==false).ToList(); 
foreach (UserType ut in userTypes) 
{ 
    ut.UserType1 = null; 
    ut.UserTypes1 = null; 
} 
return userTypes; 

где UserType1 является навигационным свойством, указывая на родительском пользователя type и UserTypes1 - это навигационное свойство, содержащее список дочернего элемента. Проблема здесь заключалась в том, что EF «фиксирует» объекты и изменяет Parent_ID на null. Если я верну его снова, EF также установит UserTypes1 ... Может быть, есть способ остановить это поведение?

ответ

1

ОК, я только что нашел, в чем проблема, и я отправляю ответ, если кто-то еще сталкивается с той же проблемой.

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

using (MyEntities context = new MyEntities()) 
{ 
    string errMsg = MyValidator.ValidateSomething(context.UserTypes,...); 
    if (!string.IsNullOrEmpty(errMsg)) throw new FaultException(errMsg); 
    //some other code here... 
    context.UserTypes.ApplyChanges(_userType);//_userType is the one that is updated 
    context.UserTypes.SaveChanges(); 
} 

Проблема заключается в том, что при выполнении валидации, контекст заполняется и при попытке сохранить изменения, есть объекты с одинаковыми значениями ключей.

Решение простое - использовать различные контексте для проверки вещей на сервере:

using (MyEntities validationContext = new MyEntities()) 
{ 
    //validation goes here... 
} 
using (MyEntities context = new MyEntities()) 
{ 
    //saving changes and other processing... 
} 

Еще один может быть:

using (MyEntities context = new MyEntities()) 
{ 
    using (MyEntities validationContext = new MyEntities()) 
    { 
     //validation 
    } 
    //saving changes and other processing... 
} 

Вот оно! Надеюсь, это может быть полезно кому-то!