ASP.NET MVC - 附加“MODELNAME"类型的实体失败,因为另一个相同类型的实体已经具有相同的主键值 [英] ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value

查看:34
本文介绍了ASP.NET MVC - 附加“MODELNAME"类型的实体失败,因为另一个相同类型的实体已经具有相同的主键值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简而言之,在 POSTing 包装模型并将一个条目的状态更改为已修改"期间抛出异常.在更改状态之前,状态设置为已分离",但调用 Attach() 确实会引发相同的错误.我使用的是 EF6.

In a nutshell the exception is thrown during POSTing wrapper model and changing the state of one entry to 'Modified'. Before changing the state, the state is set to 'Detached' but calling Attach() does throw the same error. I'm using EF6.

请在下面找到我的代码(已更改型号名称以使其更易于阅读)

Please find my code below(model names have been changed to make it easier to read)

型号

// 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"的实体失败,因为该类型的另一个实体相同类型已经具有相同的主键值.这可能发生在使用附加"方法或将实体的状态设置为如果图中的任何实体具有未更改"或已修改"冲突的键值.这可能是因为某些实体是新的并且尚未收到数据库生成的键值.在这种情况下使用'Add' 方法或 'Added' 实体状态来跟踪图形和然后将非新实体的状态设置为未更改"或已修改"为合适.

Attaching an entity of type 'A' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

有没有人看到我的代码有什么问题,或者理解在什么情况下编辑模型时会抛出这样的错误?

Does anybody see anything wrong in my code or understand in what circumstances it would throw such error during editing a model?

推荐答案

问题已解决!

Attach 方法可能对某人有所帮助,但在这种情况下它无济于事,因为在 Edit GET 控制器函数中加载文档时已经被跟踪.附加会抛出完全相同的错误.

Attach method could potentially help somebody but it wouldn't help in this situation as the document was already being tracked while being loaded in Edit GET controller function. Attach would throw exactly the same error.

我在这里遇到的问题是由函数 canUserAccessA() 引起的,该函数在更新对象 a 的状态之前加载了 A 实体.这搞砸了被跟踪的实体,并将对象的状态更改为 Detached.

The issue I encounter here was caused by function canUserAccessA() which loads the A entity before updating the state of object a. This was screwing up the tracked entity and it was changing state of a object to Detached.

解决方案是修改 canUserAccessA() 以便我加载的对象不会被跟踪.查询上下文时应调用函数 AsNoTracking().

The solution was to amend canUserAccessA() so that the object I was loading wouldn't be tracked. Function AsNoTracking() should be called while querying the context.

// 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() 一起使用,但这并不重要,因为我可以通过更改查询来实现相同的效果.

For some reason I couldnt use .Find(aID) with AsNoTracking() but it doesn't really matter as I could achieve the same by changing the query.

希望这能帮助任何有类似问题的人!

Hope this will help anybody with similar problem!

这篇关于ASP.NET MVC - 附加“MODELNAME"类型的实体失败,因为另一个相同类型的实体已经具有相同的主键值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆