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

Rob*_*ijn 17 c# entity-framework

我在我的代码中偶然发现了一个奇怪的错误.以前哪个工作,但现在有时工作.

我正在使用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();

        }
    }
Run Code Online (Sandbox Code Playgroud)

我编辑了名字以保持简单.

以下行

Context.Cs.Attach(b.C);
Run Code Online (Sandbox Code Playgroud)

抛出此错误:

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

引入此行是因为所有C实体都是静态实体.我从不想要创建一个C. 如果我删除此行,每次我将A添加到A; 创建了一个C. 这是不可取的.

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

在我的软件中的多个位置调用此EditA()方法.仅在循环(导入)中调用方法时才会出现此错误.在处理第一条记录时没有问题.但是我在第一个记录之后得到了记录中的错误.

我已经阅读了这些问题和答案,但它们并不适合我:

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

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

Rob*_*ijn 19

我修好了它.

他在Fabio Luz的回答中说:

//如果A已从上下文加载
//不附加
//如果它已在上下文之外创建
//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();

    }
}
Run Code Online (Sandbox Code Playgroud)

变更摘要:

  • 将FirstOrDefault更改为Find
  • 从上下文中获取A.

起初我删除了附加C,结果创建了一个新实体.所以我改变了这个改变.

特别感谢Fabio Luz.没有你的帮助,我无法做到这一点!


Fab*_*Luz 5

请查看以下链接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(); 
}
Run Code Online (Sandbox Code Playgroud)

注意:您不必对所有对象(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();
Run Code Online (Sandbox Code Playgroud)

编辑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();

    }
}
Run Code Online (Sandbox Code Playgroud)