【问题标题】:Multiplicity constraint violated. The role '...' of the relationship '...' has multiplicity 1 or 0..1违反了多重性约束。关系“...”的角色“...”具有多重性 1 或 0..1
【发布时间】:2013-03-30 21:59:29
【问题描述】:

我的 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;

    }

【问题讨论】:

    标签: asp.net entity-framework


    【解决方案1】:

    dbcontext 不知何故会记住添加了哪些对象。如果完全相同的对象出现两次,它...会爆炸

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

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

    而不是

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

    【讨论】:

    • 所以它将创建一个新的ChildEntity并将其添加到ChildEntities Table,然后建立关系
    • 当我的attachedEntity (MyEntity) 有一个ChildEntity 的集合时,这发生在我身上,但是我的ChildEntity 模型没有MyEntity 的集合。但我只想保留ChildEntity 的一个实例,所以当我将MyEntity 的集合添加到ChildEntity 时,我可以使用attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
    • @Reuben:最后一行的问题是,如果您启用了延迟加载,它将加载该附加实体的所有子实体。绝对不是很有效率。
    【解决方案2】:

    问题是 detachedChild.parent 应该被赋值为 attachParent。

    foreach(var detachedEntity in detachedEntities)
    {
         attachedEntity.ChildEntities.Add(detachedEntity); 
         detachedEntity.ParentEntity = attachedEntity;
    }
    

    【讨论】:

    • 这个。您会认为将孩子与新父母联系起来会使真正的父母是谁很明显,但不是。谢谢,这就是解决方案。
    • 谢谢!这解决了我的问题。 EF Y 你会这样吗?
    【解决方案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)”这个方法是什么?

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

    谢谢

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

              我遇到了类似的问题,但我的问题是在我的查询后产生的 AsNoTracking()

              我有这样的事情

              var myObject = dbContext.GetRepo&lt;myType&gt;().Query().AsNoTracking().SingleOrDefault()

              然后我用那个对象来设置另一个对象。

              var myChild = new Child { parent = myObect }

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-09-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多