В двух словах, исключение выдается во время POSTing модели оболочки и изменения состояния одной записи на «Изменено». Перед изменением состояния устанавливается состояние «Отсоединено», но вызов Attach () выдает ту же ошибку. Я использую EF6.
Пожалуйста, найдите мой код ниже (названия моделей были изменены, чтобы их было легче читать)
Модель
// Wrapper classes
public class AViewModel
{
public A a { get; set; }
public List<B> b { get; set; }
public C c { get; set; }
}
контроллер
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (!canUserAccessA(id.Value))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
var aViewModel = new AViewModel();
aViewModel.A = db.As.Find(id);
if (aViewModel.Receipt == null)
{
return HttpNotFound();
}
aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();
return View(aViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AViewModel aViewModel)
{
if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
if (ModelState.IsValid)
{
db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
db.SaveChanges();
return RedirectToAction("Index");
}
return View(aViewModel);
}
Как показано в строке выше
db.Entry(aViewModel.a).State = EntityState.Modified;
выдает исключение:
Прикрепить объект типа «A» не удалось, поскольку другой объект того же типа уже имеет такое же значение первичного ключа. Это может произойти при использовании метода «Присоединить» или установке состояния объекта на «Неизменено» или «Изменено», если какие-либо объекты на графике имеют конфликтующие значения ключей. Это может быть связано с тем, что некоторые объекты являются новыми и еще не получили значения ключей, созданные базой данных. В этом случае используйте метод «Добавить» или «Добавленное» состояние объекта для отслеживания графа, а затем установите для состояния не новых объектов значение «Без изменений» или «Изменено» в зависимости от ситуации.
Кто-нибудь видит что-то не так в моем коде или понимает, при каких обстоятельствах он может выдать такую ошибку при редактировании модели?
источник
EntityState
? Поскольку ваша сущность поступает из почтового запроса, она не должна отслеживаться текущим контекстом, я думаю, она считает, что вы пытаетесь добавить элемент с существующим идентификаторомdb
экземпляр одинаков для двух ваших действий, это может объяснить вашу проблему, поскольку ваш элемент загружается методом GET (затем отслеживается контекстом), и он может не распознать тот, который в вашем методе POST, как объект, полученный ранее ,canUserAccessA()
Загружает ли объект напрямую или как отношение другого объекта?Ответы:
Задача решена!
Attach
потенциально может помочь кому-то, но в данной ситуации он не поможет, поскольку документ уже отслеживался при загрузке в функции контроллера Edit GET. Attach выдаст точно такую же ошибку.Проблема, с которой я столкнулся, была вызвана функцией,
canUserAccessA()
которая загружает объект A перед обновлением состояния объекта a. Это приводило к сбоям отслеживаемого объекта и меняло состояние объекта наDetached
.Решением было внести поправки,
canUserAccessA()
чтобы объект, который я загружал, не отслеживался. ФункцияAsNoTracking()
должна вызываться при запросе контекста.По какой-то причине я не мог использовать
.Find(aID)
with,AsNoTracking()
но это не имеет особого значения, поскольку я мог бы добиться того же, изменив запрос.Надеюсь, это поможет кому-нибудь с подобной проблемой!
источник
using System.Data.Entity;
использоватьAsNoTracking()
.Что интересно:
Или, если вы все еще не универсальный:
похоже, решил мою проблему гладко.
источник
AddOrUpdate
это метод расширения вSystem.Data.Entity.Migrations
пространстве имен.Кажется, что объект, который вы пытаетесь изменить, не отслеживается правильно и поэтому не распознается как отредактированный, а вместо этого добавляется.
Вместо того, чтобы напрямую устанавливать состояние, попробуйте сделать следующее:
Также я хотел бы предупредить вас, что ваш код содержит потенциальную уязвимость безопасности. Если вы используете сущность непосредственно в своей модели представления, вы рискуете, что кто-то может изменить содержимое сущности, добавив правильно названные поля в отправленную форму. Например, если пользователь добавил поле ввода с именем «A.FirstName» и сущность содержала такое поле, то значение будет привязано к модели просмотра и сохранено в базе данных, даже если пользователю не разрешено изменить это при нормальной работе приложения. ,
Обновить:
Чтобы преодолеть упомянутую ранее уязвимость системы безопасности, никогда не следует раскрывать модель предметной области в качестве модели представления, а вместо этого следует использовать отдельную модель представления. Тогда ваше действие получит модель представления, которую вы можете сопоставить с моделью предметной области с помощью какого-либо инструмента сопоставления, такого как AutoMapper. Это защитит вас от изменения конфиденциальных данных пользователем.
Вот расширенное объяснение:
http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/
источник
Попробуй это:
источник
для меня локальная копия была источником проблемы. это решило это
источник
В моем случае у меня не было прямого доступа к контексту EF из моего приложения MVC.
Поэтому, если вы используете какой-то репозиторий для сохранения сущности, можно просто отсоединить явно загруженную сущность, а затем установить для привязанного EntityState значение Modified.
Пример (аннотации) кода:
MVC
вместилище
источник
Я думал, что поделюсь своим опытом по этому поводу, хотя я чувствую себя немного глупо из-за того, что не понял раньше.
Я использую шаблон репозитория с экземплярами репо, введенными в мои контроллеры. Конкретные репозитории создают экземпляр моего ModelContext (DbContext), который длится время жизни репозитория, который
IDisposable
управляется и удаляется контроллером.Проблема для меня заключалась в том, что у меня есть измененная версия штампа и строки на моих объектах, поэтому я сначала получал их, чтобы сравнить с входящими заголовками. Конечно, это загружало и отслеживало объект, который впоследствии обновлялся.
Исправление заключалось в том, чтобы просто изменить репозиторий с создания контекста один раз в конструкторе на наличие следующих методов:
Это позволяет методам репозитория заново обновлять свой экземпляр контекста при каждом использовании путем вызова
GetDbContext
или использовать предыдущий экземпляр, если они того пожелают, указав true.источник
Я добавил этот ответ только потому, что проблема объясняется на основе более сложного шаблона данных, и мне было трудно понять здесь.
Я создал довольно простое приложение. Эта ошибка произошла в действии Edit POST. Действие приняло ViewModel в качестве входного параметра. Причина использования ViewModel заключалась в том, чтобы произвести некоторые вычисления перед сохранением записи.
После того, как действие прошло проверку, например
if(ModelState.IsValid)
, я совершил ошибку, проецируя значения из ViewModel в совершенно новый экземпляр Entity. Я думал, что мне придется создать новый экземпляр для хранения обновленных данных, а затем сохранить такой экземпляр.Позже я понял, что мне нужно прочитать запись из базы данных:
и обновил этот объект. Теперь все работает.
источник
У меня была проблема с local var, и я просто отсоединил ее вот так:
Причины проблем загруженных объектов с одним и тем же ключом, поэтому сначала мы отсоединим этот объект и выполним обновление, чтобы избежать конфликта между двумя объектами с одним и тем же ключом.
источник
У меня была аналогичная проблема, после исследования в течение 2-3 дней обнаружил, что ".AsNoTracking" должен быть удален, поскольку EF не отслеживает изменения и предполагает, что изменений нет, если объект не прикреплен. Также, если мы не используем .AsNoTracking, EF автоматически знает, какой объект нужно сохранить / обновить, поэтому нет необходимости использовать Attach / Added.
источник
Используйте то,
AsNoTracking()
где вы получаете свой запрос.источник
Я столкнулся с этой ошибкой, когда
Я изменил метод B, чтобы он имел оператор using и полагался только на локальный db2 . После:
источник
Подобно тому, что говорит Люк Пуплетт, проблема может быть вызвана неправильным удалением или созданием вашего контекста.
В моем случае у меня был класс, который принимал контекст под названием
ContextService
:В моей контекстной службе была функция, которая обновляет сущность с помощью созданного экземпляра объекта сущности:
Все было в порядке, проблема была в моем контроллере, на котором я инициализировал службу. Изначально мой контроллер выглядел так:
Я изменил его на это, и ошибка исчезла:
источник
Эта проблема также может рассматриваться во время
ViewModel
дляEntityModel
картирования (с помощьюAutoMapper
, и т.д.) и пытается включать в себяcontext.Entry().State
иcontext.SaveChanges()
такой блок с использованием , как показано ниже будет решить эту проблему. Имейте в виду, чтоcontext.SaveChanges()
метод используется два раза, а не сразу после,if-block
поскольку он также должен быть в блоке using.Надеюсь это поможет...
источник
Вот что я сделал в аналогичном случае.
Эта ситуация означает, что такая же сущность уже существовала в контексте, поэтому следующее может помочь
Сначала проверьте из ChangeTracker, находится ли объект в контексте
Если он существует
источник
Мне удается исправить проблему, обновив состояние. когда вы запускаете поиск или любую другую операцию запроса в той же записи, состояние было обновлено с измененным, поэтому нам нужно установить статус на Отключено, тогда вы можете запустить изменение обновления
источник
Решаю эту проблему блоком "использующий"
Вот откуда я понял https://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum = vcses на испанском (ищите второй ответ)
источник
вы можете использовать добавленный метод, например;
но во многих случаях, если вы хотите использовать более одной модели в то время, это не сработает, потому что объект уже прикреплен к другому объекту. Итак, в это время вы можете использовать метод ADDOrUpdate Entity Migration, который просто переносит объект из одного в другой, и в результате вы не получите никаких ошибок.
источник
Очистить все состояние
dbContextGlobalERP.ChangeTracker.Entries (). Где (e => e.Entity! = null) .ToList (). ForEach (e => e.State = EntityState.Detached);
источник