Подтвердить что ты не робот

Объекты автотрассировки - AcceptChanges не может продолжаться, потому что значения ключа объекта конфликтуют с другим объектом в ObjectStateManager

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

Начну с краткого описания моей схемы.

Активы 1 --- > 1 Адрес * → 1 Район * → 1 Регион * → 1 Страна

Пакет 1 → * Активы

Использование объекта самоконтроля (STE) + WCF.

Шаги:

  • Хранить хранилище данных для списка активов.
  • Вызов хранилища данных для списка пакетов.
  • Пользователь выбирает пакет и присваивает ему некоторые активы.
  • Сохранить пакет.

На шаге 2 вызов использует активную загрузку Адресов.

from p in context.Assets.Include("Address.Area.Region.Country")

Это ошибка при попытке вызвать

context.Packages.ApplyChanges(package)

AcceptChanges не может продолжаться, потому что значения ключа объекта конфликтуют с другой объект в ObjectStateManager. Убедитесь, что значения ключа уникальны перед вызовом AcceptChanges.

ИЗМЕНИТЬ

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

Как добавить объект в свою сущность коллекция. Новый объект может иметь связанные объекты, которые содержат одинаковые ключ как один уже в коллекции. То есть Добавить новый актив, который может содержать тот же адрес, область, регион или страна.

Вот мои ограничения:

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

Я знаю о возможных решениях, предложенных Diego B Vega, но это не опции, которые я могу использовать для своего решения. У кого-нибудь есть другие идеи?

4b9b3361

Ответ 1

FYI, я написал сообщение в блоге с некоторыми дополнительными предложениями о том, что я уже ответил на форумах EF. Здесь - это сообщение в блоге.

Ответ 2

Вы считали, что просто отказываетесь от ORM и возвращаетесь к нормальному доступу, если знаете, что я имею в виду: -)

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

Тем более, что у вас есть очень чистая схема - это довольно простые запросы и прямые обновления.

Ответ 3

Я столкнулся с той же проблемой и, наконец, придумал решение. Основная идея состоит в том, чтобы предотвратить присоединение определенного типа навигационного класса к ObjectContext. Вот что я сделал:

  • Изменен шаблон context.tt, чтобы сделать класс SelfTrackingEntitiesContextExtensions частичным.
  • Скопируйте 2 функции ApplyChanges в новый созданный Custom.Context.Extension.cs и переименуйте их как CustomApplyChanges. Каждый из них будет иметь один дополнительный параметр в виде массива Type

public static void CustomApplyChanges (это Контекст ObjectContext, строка entitySetName, объект TEntity, Тип [] excludeTypes), где TEntity: IObjectWithChangeTracker

  1. Добавить условие в цикл for для исключения любого типа класса, содержащегося в массиве excludeTypes.

область обработки Начальное состояние сущности

foreach (IObjectWithChangeTracker changedEntity в entityIndex.AllEntities.Where(x = > x.ChangeTracker.State == ObjectState.Deleted && & ! ExcludeTypes.Contains(x.GetType()))){HandleDeletedEntity (контекст, entityIndex, allRelationships, changedEntity); }

foreach (IObjectWithChangeTracker changedEntity в entityIndex.AllEntities.Where(x = > x.ChangeTracker.State != ObjectState.Deleted & &! ExcludeTypes.Contains(x.GetType()))){HandleEntity (контекст, entityIndex, allRelationships, changedEntity); }

endregion

  1. Использование

Тип [] excludeTypes = {typeof (Asset), typeof (Адрес), typeof (Region)};

rep.Entities.CustomApplyChanges(entity, excludeTypes); var changedEntry = rep.Context.ObjectStateManager.GetObjectStateEntries > (System.Data.EntityState.Added | System.Data.EntityState.Modified | System.Data.EntityState.Deleted);                     foreach (var e in changedEntry)                     {                         if (excludeTypes.Any(c = > c == e.Entity.GetType()))                         {                             rep.Context.Detach(e.Entity);//Отключить объекты без изменений                         }                     }

Ответ 4

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

... что-то вроде этого:

var countryToId = address.CountryToId;
var countryFromId = address.CountryFromId;
documentAddress.CountryTo = null;
documentAddress.CountryFrom = null;
documentAddress.CountryToId = countryToId;
documentAddress.CountryFromId = countryFromId;

Ответ 5

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

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

Поскольку в этой ситуации мне не нужно самостоятельное отслеживание, я отключил его как:

dbcontext.entity.MergeOption = System.Data.Objects.MergeOption.NoTracking;