C# 附加类型为'的实体;X';失败,因为另一个相同类型的实体

C# 附加类型为'的实体;X';失败,因为另一个相同类型的实体,c#,entity-framework,C#,Entity Framework,我在代码中偶然发现了一个奇怪的错误。以前是有效的,但现在有时有效 我正在使用EF6编辑具有某些关系的实体。 要不编辑关系,我将其“附加”(参见示例代码) 我编辑了这些名字以保持简单 下一行 Context.Cs.Attach(b.C); 抛出此错误: 附加类型为“C”的实体失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实体状态设置为“Unchanged”或“Modified”时可能会发生这种情况。这可能是因为某些实体是新的

我在代码中偶然发现了一个奇怪的错误。以前是有效的,但现在有时有效

我正在使用EF6编辑具有某些关系的实体。 要不编辑关系,我将其“附加”(参见示例代码)

我编辑了这些名字以保持简单

下一行

Context.Cs.Attach(b.C);
抛出此错误:

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

引入这一行是因为所有C实体都是静态实体。我从不希望创建一个C。如果我删除这行,每次我都会在a中添加B;创建一个C。这是不可取的

额外信息:
A有一个B的列表
B有一个C

这个EditA()方法在我的软件中的多个位置被调用。只有在循环(导入)中调用该方法时,才会出现此错误。处理第一条记录时没有问题。但是在第一次之后,我在记录中发现了错误

我读过这些问题和答案,但它们对我不起作用:


  • 请看下面的链接

    如果您知道数据库中已经存在一个实体,但可能已经对其进行了更改,那么您可以告诉上下文附加该实体并将其状态设置为“已修改”。例如:

    var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; 
    
    using (var context = new BloggingContext()) 
    { 
        context.Entry(existingBlog).State = EntityState.Modified; 
    
        // Do some more work...  
    
        context.SaveChanges(); 
    }
    
    注意:您不必对所有对象(A、B和C)都这样做,只需对A

    编辑1

    根据您的评论,尝试以下方法:

    //check if 
    var _b = Context.Bs.Find(ThisIsB.BId);
    
    if (_b != null)
      //b doesn't exist, then add to the context
      //make sure that the primary key of A is set.
      //_b.PrimaryKeyOfA = someValue;
      Context.Bs.Add(_b);
    else
     //b already exists, then modify the properties
     //make sure that the primary key of A is set.
    
    Context.SaveChanges();
    
    编辑2

    我没有测试,但它应该可以工作

    public void EditA(A ThisIsA, B ThisIsB)
    {
        using (var Context = new LDZ_DEVEntities())
        {
            //if A has been loaded from context
            //dont attach it
            //if it has been created outside of the context
            //Context.Entry(ThisIsA).State = EntityState.Modified;
    
            var _b = Context.Bs.Find(ThisIsB.BId);
    
            if (_b == null)
            { 
                _b = ThisIsB;
            }
    
            ThisIsA.Bs.Add(_b);
    
            Context.SaveChanges();
    
        }
    }
    
    我修好了

    在法比奥·卢兹的回答中,他说:

    //如果已从上下文加载 //不要附加它
    //如果它是在上下文之外创建的
    //Context.Entry(ThisIsA.State=EntityState.Modified

    这让我思考,因此我将代码编辑为:

    public void EditA(A ThisIsA, B ThisIsB)
    {
        using (var Context = new LDZ_DEVEntities())
        {
            var a = Context.As.Find(ThisIsA.AId);
    
            //var b = Context.Bs.FirstOrDefault(x => x.BId == ThisIsB.BId);
            var b = Context.Bs.Find(ThisIsB.BId);
    
            if (b != null)
                Context.Bs.Attach(b);
            else
                b = ThisIsB;
    
            if (b.C != null)
                Context.Cs.Attach(b.C);
    
            a.Bs.Add(b);
    
            Context.SaveChanges();
    
        }
    }
    
    变更摘要:

    • 更改了FirstOrDefault以查找
    • 从上下文中获取信息
    起初,我删除了C的附件,因此创建了一个新实体。 所以我扭转了这个变化


    特别感谢法比奥·卢兹。没有你的帮助,我不可能做到这一点

    另一种方法(取决于您的情况)是简单地分离实体状态

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Modify(Model model)
    {
    
    if (model.Image == null)
    {
    Model item = db.Model.Find(model.Name);
    
    // Get the Content needed:
    model.Image = item.Image;
    
    // Detach the Comparison State:
    db.Entry(item).State = EntityState.Detached;
    }
    
    if (ModelState.IsValid)
    {
    db.Entry(model).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
    }
    
    return View(model);
    }
    
    这样做:
    db.Entry(item).State=EntityState.DetachedEntityFramework的状态仍然完好无损,您可以将更改保存到数据库(db)中


    希望这有帮助

    如果A有一个B列表,B有一个C,您只需要附加A。B和C将自动插入…C是静态实体。我从不想插入它们。只有在B不存在的情况下才需要插入B。你所说的“静态实体”是什么意思?根据您的代码,有一个C实体的数据集。它们怎么可能是“静态的”?静态的,就像在中一样,有一组C实体。那些永远不会被创建/更新/删除的相关帖子可能会有所帮助:不幸的是,这并没有解决问题。该方法用于将a B添加到a。。所以我只想登记A和B之间的变化。。如果B不存在。。B将被创建(发生在A.Bs.Add(B)中)。查看编辑1如果您查看我的示例代码,您可以看到我已经在执行类似于您的编辑的操作。当我尝试附加C时抛出错误。或者您认为它是由其他原因引起的吗?我相信我们缺少了一些东西。你能给我解释一下你到底想做什么吗?我这么说是因为你的编辑方法有3个参数,我觉得很奇怪。。。没必要,我理解这种混乱。C不是作为参数存在的,我在那里添加了它,看看它是否可以解决这个问题。我已经编辑了我问题中的代码。欢迎你,伙计!谢谢你的夸奖。将自己的帖子标记为将来帮助他人的答案:这对我真的很有帮助-我在一个单独的变量中加载了我正在编辑的实体,没有想到变更跟踪器会跟踪不同的版本并比较两者。。一旦我删除了另一个引用,那么对EntityState.Modified的更改就非常有效。谢谢。没问题,keithl8041,帮我把这篇文章投到有用的地方,这样我们就能帮助人们找到可能对他们有帮助的答案
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Modify(Model model)
    {
    
    if (model.Image == null)
    {
    Model item = db.Model.Find(model.Name);
    
    // Get the Content needed:
    model.Image = item.Image;
    
    // Detach the Comparison State:
    db.Entry(item).State = EntityState.Detached;
    }
    
    if (ModelState.IsValid)
    {
    db.Entry(model).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
    }
    
    return View(model);
    }