Объект с тем же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом
В принципе, у меня есть таблица, которая содержит несколько свойств для компании. Это таблица "master", и их идентификатор используется во многих других таблицах. Я в основном нахожу их идентификатор с помощью этого метода:
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");
}
(FYI - Company
- это модель /POCO, представляющая компанию, а сама Company
- это данные формы.)
После добавления этого, если я отредактирую идентификатор в данных формы, он работает как ожидалось и вызывает "Ошибка безопасности", однако, если нет ошибки, и я продолжаю, я получаю ошибку в вопросе.
"Объект с тем же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом.
Я считаю, что это потому, что EF каким-то образом обнаруживает и удерживает первые данные, но я просто не уверен, как их исправить.
Любые советы?
Edit-
--update -
Если вы можете понять, чего я пытаюсь достичь, есть ли лучший способ обойти это?
Ответы
Ответ 1
Если вы загружаете объект из контекста, вы не можете снова присоединить объект с тем же ключом. Первый объект по-прежнему хранится во внутреннем кэше контекста, и контекст может содержать только один экземпляр с заданным значением ключа для каждого типа (он называется идентификационной картой и Я описал его здесь в других ситуация).
Вы можете решить это, отделив прежний экземпляр, но вам этого не нужно. Если вам нужно сохранить только новые значения, вы можете использовать это:
- API ObjectContext:
context.YourEntitySet.ApplyCurrentValues(newEntity);
- API-интерфейс DbContext:
context.Entry(oldEntity).CurrentValues.SetValues(newEntity);
Ответ 2
Немного о помощи для вас, если вы не знаете, как найти oldEntity
, как в соответствии с Ladislav:
var entityKey = context.NewEntitySet.Create().GetType().GetProperty("Id").GetValue(newEntity);
factory.Entry(context.Set<NewEntityType>().Find(entityKey)).CurrentValues.SetValues(newEntity);
Ответ 3
Как ясно говорится об ошибке: вам нужно убедиться, что получить существующий элемент и изменить данные этого элемента с обновленной информацией и сохранить его. Вы не столкнетесь с этой проблемой, если вы обновите очень конкретную информацию, а не ключевую информацию, такую как 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);
...
Ответ 4
Только что увидел этот вопрос вчера. Перед обновлением необходимо отключить cuco. Проверьте решение в этом ответе