23

我的 DbContext 出现以下错误:“违反了多重性约束。关系‘MyModel.FK_ChildEntities_MyEntities’的角色‘MyEntity’的多重性为 1 或 0..1。”

使用 ASP.NET,实体框架 4

使用分离的实体

我第二次尝试将实体重新附加到 dbcontext 时发生该错误。场景是一次不成功的保存,然后重新尝试。

我在会话中有一个分离的实体。用户更改表单中的属性,添加内容,删除内容,最后单击保存。我从 dbcontext 的新实例中获取实体的附加副本,将分离实体的更改应用到附加实体,验证,找到错误并中止。用户更改任何内容并再次保存。

在第二次保存时,整个保存过程会重复,只是这一次一切都下地狱了。几乎所有内容都是重复的,导致一个错误或另一个错误或所有错误。仅应作为引用的视图和查找表中的值被创建为新的并重新分配了 id。我已经能够解决大多数这些问题,但我留下了多重性错误。子元素被创建为其他子元素的精确副本,直到唯一的 id,仅处于已添加状态。或者,如果我引用某些属性,而不是克隆一个未修改的孩子,它会删除新的。无论哪种方式,都没有像第一次那样执行代码。

每次保存尝试时,我都会丢弃 dbcontext 的实例和附加的实体。我认为这足以恢复任何更改,但必须有一些东西存在。唯一没有丢弃或重置的是分离的实体,它正在会话中,但我没有对其进行任何更改。至少不是直接的。

代码(非常简化)是这样的:

void Save()
{
using (var context = new MyContext())
{
   // detached entity from session
   MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];

   // attached entity from context
   MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);       


   // <remove children representing lookup table elements from detachedEntity to prevent duplicates>
   // <remove children representing view elements from detachedEntity to prevent duplicates>


   // <apply changes from detachedEntity to attachedEntity>


   // <add new children>
   // <remove deleted children>
   // <update modified children>


   // <set entity state to unchanged on view and lookup elements of attachedEntity to ensure no duplicates...>


   // <validate>


   if (errors.count>0)
     // <report errors>
   else
     context.SaveChanges();
}
}

例如,这会产生多重性错误:

// represents first save:
    using (var context = new MyContext())
    {
       // detached entity from session
       MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];

       // attached entity from context
       MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);       

       int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;

       attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());

       int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug2 == 1;

    }

// represents second save:
    using (var context = new MyContext())
    {
       // detached entity from session
       MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];

       // attached entity from context
       MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);    

       int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;

       attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());

       int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // multiplicity error;

    }
4

8 回答 8

21

dbcontext 以某种方式记住添加了哪些对象。如果完全相同的物体出现两次,它......吹

而不是从我的分离实体添加子实体到附加的实体,我应该一直在创建每个孩子的新副本

ChildEntity detachedChild = detachedEntity.ChildEntities.First();
attachedEntity.ChildEntities.Add(new ChildEntity { 
   propertyA = detachedChild.propertyA,
   propertyB = detachedChild.propertyB
});

代替

attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
于 2013-04-09T18:23:46.173 回答
10

问题是应该为 detachedChild.parent 分配 attachParent。

foreach(var detachedEntity in detachedEntities)
{
     attachedEntity.ChildEntities.Add(detachedEntity); 
     detachedEntity.ParentEntity = attachedEntity;
}
于 2013-05-25T23:05:12.583 回答
3

你想要做的是这样的:

ChildEntity childEntity = new ChildEntity()
{
  //do mapping or provide data EXCEPt THE PRIMARY KEY
}

foreach(ParentEntity parentEntity in parentEntities)
{
    parentEntity.Add(childEntity);
}

_dbContext.SaveChanges();

结果

Multiplicity constraint violated. The role '…' of the relationship '…' has multiplicity 1 or 0..1

错误信息的原因是

每次 _dbContext 将 childEntity 添加到某个 parentEntity 时,它会将生成的主键设置为 childEntity,因此在 foreach 的第二个循环中,主键将被复制

修复方法是 - 方法 #1 - 适用于简单场景

foreach(ParentEntity parentEntity in parentEntities)
{
    //Make a new object every time
    ChildEntity childEntity = new ChildEntity()
    {
      //do mapping or provide data EXCEPt THE PRIMARY KEY
    }

    parentEntity.Add(childEntity);
}

_dbContext.SaveChanges();

修复方法是 - 方法 #2 - 适用于复杂场景

using YOUR_PROJECT.ANY_FOLDER.DeepCopyExtensions;    

ChildEntity childEntity = new ChildEntity()
{
  //do mapping or provide data EXCEPt THE PRIMARY KEY
}

foreach(ParentEntity parentEntity in parentEntities)
{
    //makes a copy of the childEntity object and pass it to the _dbContext, after saving each copy will be separated and the original object childEntity wont be touched 
    parentEntity.Add(DeepCopyByExpressionTrees.DeepCopyByExpressionTree(childEntity));
}

_dbContext.SaveChanges();

这个方法“DeepCopyByExpressionTrees.DeepCopyByExpressionTree(childEntity)”是什么?

在此处查看此项目,下载源代码,并且仅将类文件“DeepCopyByExpressionTrees.cs”作为帮助类包含到您的项目中,并在任何地方开始使用它。

谢谢

于 2020-01-12T18:05:03.923 回答
1

确保检查您尝试添加的对象的属性。在我的情况下,它错误地在每个不喜欢的添加上引用了相同的无效对象,因此引发了与您在这里相同的错误。

于 2014-01-27T04:29:17.613 回答
0

我有一个类似的问题,但我的问题是AsNoTracking()在我的查询之后产生的。

我有这样的事情

var myObject = dbContext.GetRepo<myType>().Query().AsNoTracking().SingleOrDefault()

然后稍后我使用该对象设置另一个对象。

var myChild = new Child { parent = myObect }

显然 EntityFramework 试图创建一个全新的对象,因此导致多重性错误。

于 2020-03-11T18:01:07.087 回答
0

我通过使父实体中的子集合成为虚拟来解决此问题。这允许人们在其子集合不更改时轻松更新实体,对我来说,这是大多数时间。

于 2018-09-20T12:03:12.250 回答
0

当我的导航属性尚未设置或导航属性属于错误的 Code First DBContext 时,我遇到了此错误

于 2017-09-29T06:51:31.697 回答
0

英孚 6 更新

对我来说,将对象状态设置为添加听起来也合乎逻辑

ChildEntity detachedChild = detachedEntity.ChildEntities.First();
var newChild = new ChildEntity { 
   propertyA = detachedChild.propertyA,
   propertyB = detachedChild.propertyB
});

// Mark all added entity entity state to Added
 attachedEntity.ChildEntities.Add(newChild );
                        db.Entry(newChild ).State = EntityState.Added;

http://www.entityframeworktutorial.net/EntityFramework4.3/update-one-to-many-entity-using-dbcontext.aspx

于 2015-08-17T12:22:24.637 回答