当前位置: 首页 > 知识库问答 >
问题:

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

胡沈义
2023-03-14

我在代码中偶然发现了一个奇怪的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”时可能会发生这种情况。这可能是因为某些实体是新的,尚未收到数据库生成的键值。在这种情况下,请使用“Add”方法或“Added”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“Unchanged”或“Modified”。

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

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

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

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

>

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

共有3个答案

姬墨竹
2023-03-14

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

[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。条目(项目)。状态=实体状态。分离的 EntityFramework的状态仍然保持不变,您可以将更改保存到数据库(db)中。

希望这有帮助!

葛越泽
2023-03-14

查看以下链接https://msdn.microsoft.com/en-us/data/jj592676.aspx

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

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

    }
}
彭令秋
2023-03-14

我把它修好了。

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

//如果从上下文中加载了,请不要附加它,如果它是在上下文之外创建的。条目(本ISA)。状态=实体状态。已修改

这让我思考,所以我将代码编辑为:

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的附加,结果这创建了一个新实体。所以我逆转了这个变化。

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

 类似资料:
  • 错误消息: 正在附加“FaridCRMData”类型的实体。模型。“Customer”失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的 我的代码: FactorService. BaseService.cs:

  • 让我快速描述一下我的问题。 我有5个客户的5个数据库,每个数据库都有一个名为SubnetSettings的表。 我已经创建了一个下拉列表来选择一个客户,并将显示属于所选客户的SubnetSSet表,并允许我创建、编辑和删除。 我可以毫无问题地创建、删除,但当我想编辑数据时,它会带来错误: /运输管理系统应用程序中的服务器错误。 附加“CFS”类型的实体。领域实体。SubnetSettings“失败

  • 错误消息:附加类型的实体失败,因为相同类型的另一个实体已具有相同的主键值。 问题:我如何以类似于下面代码中AttachActivity方法所示的方式附加实体? 我必须假设上面错误消息的“另一个实体”部分指的是内存中存在但超出范围的对象(?)。我之所以注意到这一点,是因为我尝试附加的实体类型的DBSet的本地属性返回零。 我有理由相信实体不存在于上下文中,因为我遍历代码并在创建上下文时观察上下文。实

  • 我的WebApi应用程序有一个小问题。当我将新实体添加到我的数据库时,会出现这个问题。 实体: 要在其中向数据库中添加新赌注实体的代码: 在此位置,将我的实体添加到DB中(DB:我的SQL) 调用save方法时,代码会引发以下异常: 附加“WebCar. Domain. Entities. Lot”类型的实体失败,因为另一个相同类型的实体已经具有相同的主键值。如果图形中的任何实体具有冲突的键值,则

  • 简而言之,在发布包装器模型并将一个条目的状态更改为“已修改”期间引发异常。更改状态之前,状态设置为“已分离”,但调用Attach()会引发相同的错误。我正在使用EF6。 请在下面找到我的代码(型号名称已更改以便于阅读) 模型 控制器 如上图所示 引发异常: 附加类型为“A”的实体失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实

  • 我正在使用automapper重构一些代码,请参见下面注释掉的旧代码。 编辑:请注意,属性对象是从基础设置的,因此建议的重复问题不适用。 当状态设置为modified时,我得到以下异常:; 附加“M.Survey”类型的实体。ServiceLayer。模型属性“”失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实体状态设置为“U