附加类型实体失败,因为相同类型的另一个实体已经具有相同的主键值。

Posted

技术标签:

【中文标题】附加类型实体失败,因为相同类型的另一个实体已经具有相同的主键值。【英文标题】:Attaching an entity of type failed because another entity of the same type already has the same primary key value. 【发布时间】:2014-07-18 07:25:37 【问题描述】:

让我快速描述一下我的问题。

我有 5 个客户的 5 个数据库每个客户都有同一个表,称为 SubnetSettings

我已经创建了一个下拉列表来选择一个客户,并将显示属于所选客户的 SubnetSetting 表,并允许我创建、编辑和删除。

我可以毫无问题地创建、删除,但是当我想编辑数据时会出现错误:

“/TMS”应用程序中的服务器错误。

附加类型为“CFS.Domain.Entities.SubnetSettings”的实体失败,因为同一类型的另一个实体已经具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,使用 'Add' 方法或 'Added' 实体状态来跟踪图形,然后将非新实体的状态适当地设置为 'Unchanged' 或 'Modified'。

这是我在控制器中的编辑

    // GET: /SubnetSettings/Edit1/5   
    public ActionResult Edit1(short? id)  
    
        if (id == null)
        
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        
        SubnetSettings subnetsettings = detailView.SubnetSettings.SingleOrDefault(t => t.Id == id); 
        if (subnetsettings == null)
        
            return HttpNotFound();
         
        return View(subnetsettings);
    


    // POST: /SubnetSettings/Edit1/5   
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit1([Bind(Include = "Id,Name,fDialUp,fPulse,fUseExternalGSMModem,fGsmDialUp,bUploadMethodId")] SubnetSettings subnetsettings)
    
        if (ModelState.IsValid)
            
                templateDb2.Save(subnetsettings);   
                return RedirectToAction("Index");
            
        return View(subnetsettings);
    

这是 EF 中的 Save 方法

     public SubnetSettings Save(SubnetSettings subnetsettings) 

     if (subnetsettings.Id == 0)                        
         context.SubnetSettings.Add(subnetsettings);
     
     else 

         context.SubnetSettings.Attach(subnetsettings);               
         context.Entry(subnetsettings).State = EntityState.Modified; 
     
        context.SaveChanges();
        return subnetsettings;
    

我知道很难理解其他人的代码。因此,任何推荐或建议都非常感谢。

【问题讨论】:

请看我在ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value上的回答。 【参考方案1】:

客观综合答案: 您尝试更新的对象不是来自基础,这是错误的原因。该对象来自视图的帖子。

解决方案是从基础中检索对象,这将使实体框架知道并管理上下文中的对象。然后,您将必须从 View 中获取每个已更改的值,并包含在 Entity 控制的对象中。

// POST: /SubnetSettings/Edit1/5   
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit1([Bind(Include = "Id,Name,fDialUp,fPulse,fUseExternalGSMModem,fGsmDialUp,bUploadMethodId")] SubnetSettings subnetsettings)

    if (ModelState.IsValid)
        
            //Retrieve from base by id
            SubnetSettings objFromBase = templateDb2.GetById(subnetsettings.Id);

            //This will put all attributes of subnetsettings in objFromBase
            FunctionConsist(objFromBase, subnetsettings)

            templateDb2.Save(objFromBase);   
            //templateDb2.Save(subnetsettings);   

            return RedirectToAction("Index");
        
    return View(subnetsettings);

【讨论】:

为了避免烦人的消息,我必须从数据库中加载记录才能使用context.Entry(obj).State = EntityState.Modified; 感谢您的澄清。我将我的 ItemsSource 绑定到 XAML 中的实体框架模型。然后我请求了 ItemsSource 变量(它是一个 ObservableCollection)并尝试更新它。这导致了上面的错误。然后我尝试通过代码设置 ItemsSource:ItemsSource = database_context.model.Local,它解决了我的问题。 一旦我读到“您尝试更新的对象不是来自基础,这是错误的原因。对象来自视图的帖子。”这一切都让我明白了。问题解决了。谢谢。【参考方案2】:

我不确定以下行是否符合您的预期:

Mapper.Map<Category, Category>(categoryFromViewModel, categoryFromBase);

我认为以下是您想要的:

Category categoryFromBase = Mapper.Map<Category>(categoryFromViewModel)

【讨论】:

【参考方案3】:

为了消除错误,我在更新之前使用 AutoMapper 将视图模型对象复制到基础对象中。

Category categoryFromBase = Repository.GetById(categoryFromViewModel.Id);
Mapper.CreateMap<Category, Category>();

Mapper.Map<Category, Category>(categoryFromViewModel, categoryFromBase);
Repository.Save(categoryFromBase);   

【讨论】:

以上是关于附加类型实体失败,因为相同类型的另一个实体已经具有相同的主键值。的主要内容,如果未能解决你的问题,请参考以下文章

附加类型为“”的实体失败,因为另一个实体具有相同的主键值

无法跟踪实体类型的实例,因为已经在跟踪具有相同键值对的另一个实例 'Id'

使用实体框架编辑以前的数据

附加类型的实体失败,因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Mo

EF报错 附加类型model失败

无法跟踪实体类型的实例,因为已在跟踪具有相同键值的另一个实例