Объект с таким ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним ключом


в принципе, у меня есть таблица, которая содержит несколько свойств для компании. Это "главная" таблица, и их идентификатор используется во многих других таблицах. Я в основном найти их идентификатор с помощью этого метода:

private Company currentcompany()
    {
        Company cuco = db.Companies.Single(x => x.username == User.Identity.Name);
        return cuco;
    }

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

используя данные Tamper в Firefox (и я представляю Fidler / многие другие), я мог бы легко изменить скрытый идентификатор и изменить другие детали компании.

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

        Company cuco = currentcompany();

        if (company.id != cuco.id)
        {
            return Content("Security Error");
        }

(к вашему сведению -Company это модель / POCO, представляющая компанию, и company сама форма данных.)

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

"объект с таким ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом."

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

какие-либо советы?

изменить- --обновление--

если вы можете понять, что я пытаюсь достичь, есть ли лучший способ обойти это?

4 59

4 ответа:

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

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

  • ObjectContext API:context.YourEntitySet.ApplyCurrentValues(newEntity);
  • DbContext API:context.Entry(oldEntity).CurrentValues.SetValues(newEntity);

просто немного помочь, если вы не знаете как найти oldEntity как по Ладиславу:

var entityKey = context.NewEntitySet.Create().GetType().GetProperty("Id").GetValue(newEntity);

factory.Entry(context.Set<NewEntityType>().Find(entityKey)).CurrentValues.SetValues(newEntity);

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

 public virtual void Update(TEntity entity)
    {
        _context.Entry(entity).State = EntityState.Modified;

        this._context.SaveChanges();
    }

использование будет -

 public async Task<bool> UpdateVendorItem(string userId, Vendor modified)
    {

        try
        {
            var existing = await this.GetVendors().SingleOrDefaultAsync(a => a.Id == modified.Id);


            //Set updated info
            existing.VendorName = modified.VendorName;

            //Update address information
            existing.Address.AddressLine1 = modified.Address.AddressLine1;
            ... 

            await _vendorRepository.UpdateAsync(existing);

    ...

только что видел этот вопрос вчера. Вам нужно отсоединить cuco перед обновлением. Проверьте решение в этом ответ