多重性约束被违反。关系“…”的角色“…”具有多重性1或0..1。

27
我从DbContext中收到以下错误信息:“Multiplicity constraint violated。The role 'MyEntity' of the relationship 'MyModel.FK_ChildEntities_MyEntities' has multiplicity 1 or 0..1."。
使用ASP.NET,Entity Framework 4。
处理一个分离的实体。
当我尝试将实体重新附加到DbContext时出现错误。场景是一个不成功的保存操作后进行的再次尝试。
我有一个在会话中的分离实体。用户在表单中更改属性、添加和删除内容,最终点击保存。我从一个新的DbContext实例中获取一个已附加的实体副本,将来自分离实体的更改应用于已附加的实体,进行验证并查找错误并中止。用户进行任何更改并再次保存。
在第二次保存时,整个保存过程重复,但这一次所有事情都变得非常混乱。几乎所有内容都被复制,导致一个或多个错误。视图和查找表中的值只应该是引用,并且会创建新的并重新分配id。其中大部分问题我已经能够解决,但我还面临着多重性错误。子元素被创建为其他子元素的完全副本,直到唯一id,仅处于Added状态。或者,如果引用某些属性,则不是克隆未修改的子元素,而是删除新的子元素。无论哪种方式,没有任何代码像第一次运行那样执行。
我在每次保存尝试时丢弃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;

    }
8个回答

24

在某种程度上,dbcontext会记住添加到其中的对象。如果完全相同的对象出现两次,它会崩溃。

我应该创建每个子实体的新副本,而不是将来自我的分离实体的子实体添加到已附加的实体中。

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

1
它将创建一个新的ChildEntity并将其添加到ChildEntities Table,然后建立关联。 - Mohsen
当我的attachedEntity(MyEntity)有一个ChildEntity的集合时,我遇到了这个问题,但是我的ChildEntity模型没有MyEntity的集合。但是我只想保留一个ChildEntity实例,所以当我将MyEntity的集合添加到ChildEntity时,我可以使用attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First()); - Reuben
1
@Reuben:最后一行的问题在于,如果启用了延迟加载,它将会加载所有附加实体的ChildEntities。绝对不是很高效的做法。 - Jonathan Wood

12
问题在于detachedChild.parent应该被分配给attachedParent。
foreach(var detachedEntity in detachedEntities)
{
     attachedEntity.ChildEntities.Add(detachedEntity); 
     detachedEntity.ParentEntity = attachedEntity;
}

5
这个。你可能会认为将一个孩子附着在新的父母身上会让真正的父母显而易见,但不是这样的。谢谢,这就是解决方案。 - CAD bloke
谢谢!这解决了我的问题。EF 为什么要这样呢? - matao

4
您正在尝试做的是类似于:
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" 包含到你的项目中作为帮助类,并在任何地方开始使用。

谢谢


1

确保检查要添加的对象的属性。在我的情况下,它错误地在每次添加时引用相同的无效对象,这是不喜欢的,因此会抛出你在这里看到的相同错误。


0
我通过将父实体中的子集合设置为虚拟来解决了这个问题。这样可以在其子集合不改变时轻松更新实体,而这对我来说大多数情况下都是如此。

0

当我有未设置的导航属性或者属于错误的 Code First DBContext 的导航属性时,我遇到了这个错误。


0

我曾经遇到过类似的问题,但是我的问题是由于查询后使用了AsNoTracking()方法。

我的代码大概是这样的:

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

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

var myChild = new Child { parent = myObect }

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


0

EF 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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接