简而言之,在POST包装模型和将一个条目的状态更改为“已修改”的过程中会引发异常。在更改状态之前,将状态设置为“已分离”,但是调用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”的实体失败,因为相同类型的另一个实体已经具有相同的主键值。如果图形中的任何实体具有相互冲突的键值,则使用“附加”方法或将实体的状态设置为“不变”或“修改”时,可能会发生这种情况。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,请使用“添加”方法或“已添加”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。
是否有人在我的代码中看到任何错误,还是了解在什么情况下在编辑模型期间会引发此类错误?
问题解决了!
Attach该方法可能会帮助某人,但在这种情况下将无济于事,因为在将文档加载到Edit GET控制器功能中时已经对其进行了跟踪。附加将引发完全相同的错误。
Attach
我在这里遇到的问题是由canUserAccessA()在更新对象a的状态之前加载A实体的函数引起的。这正在破坏被跟踪的实体,并将对象的状态更改为Detached。
canUserAccessA()
Detached
解决方案是进行修改,canUserAccessA()以便不会跟踪正在加载的对象。AsNoTracking()查询上下文时应调用函数。
AsNoTracking()
// User -> Receipt validation private bool canUserAccessA(int aID) { int userID = WebSecurity.GetUserId(User.Identity.Name); int aFound = db.Model.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count(); return (aFound > 0); //if aFound > 0, then return true, else return false. }
出于某种原因,我无法.Find(aID)与之配合使用,AsNoTracking()但这并不重要,因为我可以通过更改查询来实现相同的目的。
.Find(aID)
希望这会帮助任何有类似问题的人!