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

本文关键字:另一个 实体 因为 同类型 类型 失败 | 更新日期: 2023-09-27 17:50:16

我在代码中发现了一个奇怪的bug。这是以前工作,但现在有时工作

我使用EF6来编辑一个具有一些关系的实体。为了不编辑关系,我"附加"它们(参见示例代码)。

public void EditA(A ThisIsA, B ThisIsB)
    {
        using (var Context = new LDZ_DEVEntities())
        {
            Context.As.Attach(ThisIsA);
            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);
            ThisIsA.Bs.Add(b);
            Context.SaveChanges();
        }
    }

我对名字进行了编辑,以保持简单。

下一行

Context.Cs.Attach(b.C);

抛出这个错误:

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

引入这一行是因为所有的C实体都是静态实体。我从来不想要一个C。如果我去掉这条线,每次我把B加到a;创建一个C。这是不可取的。

额外信息:


A有一个B的列表
B有一个C

这个EditA()方法在我的软件的多个地方被调用。此错误仅在循环(导入)中调用该方法时出现。在处理第一个记录时没有任何问题。但是我在第一个记录之后得到错误。

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

  1. ASP。. NET MVC -附加类型为'MODELNAME'失败,因为相同类型的另一个实体已经具有相同的主键值

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

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

我修好了。

在Fabio Luz的回答中,他说:

//如果A是从context中加载的
//不附加
//如果它是在上下文之外创建的
//Context.Entry (ThisIsA)。

这引起了我的思考,所以我编辑了我的代码:

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更改为查找
  • 从上下文中获取A

首先,我删除了C的Attach,因此创建了一个新实体。所以我把这个改变反过来。

特别感谢Fabio Luz。没有你的帮助,我做不到!

请看下面的链接https://msdn.microsoft.com/en-us/data/jj592676.aspx

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

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();
    }
}

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

[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.Detached;, EntityFramework的状态仍然是完整的,你可以将更改保存到数据库(db)。

希望这对你有帮助!

相关文章: