我从DbContext收到以下错误:“违反了多重约束。关系'MyModel.FK_ChildEntities_MyEntities'的角色'MyEntity'具有多重性1或0..1。”
使用ASP.NET,Entity Framework 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;
}
答案 0 :(得分:15)
以某种方式dbcontext会记住添加了哪些对象。如果完全相同的对象出现两次,那么...打击
而不是将我的分离实体中的子实体添加到附加的实体,我应该创建每个孩子的新副本
ChildEntity detachedChild = detachedEntity.ChildEntities.First();
attachedEntity.ChildEntities.Add(new ChildEntity {
propertyA = detachedChild.propertyA,
propertyB = detachedChild.propertyB
});
而不是
attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
答案 1 :(得分:7)
问题是应该为detaachedChild.parent分配attachParent。
foreach(var detachedEntity in detachedEntities)
{
attachedEntity.ChildEntities.Add(detachedEntity);
detachedEntity.ParentEntity = attachedEntity;
}
答案 2 :(得分:2)
您要尝试执行的操作类似于:
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”作为帮助程序类包含到您的项目中,并在任何地方开始使用。
谢谢
答案 3 :(得分:1)
确保检查您要添加的对象的属性。在我的情况下,它错误地引用了它不喜欢的每个添加上的相同无效对象,因此抛出了你在这里的相同错误。
答案 4 :(得分: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;
答案 5 :(得分:0)
当我有未设置的导航属性或属于错误的Code First DBContext的导航属性时,我遇到此错误
答案 6 :(得分:0)
我通过将父实体中的子集合虚拟化来解决此问题。这样一来,在大多数情况下,子实体不更改时,即可轻松更新实体。
答案 7 :(得分:0)
我遇到了类似的问题,但是我的查询后是由AsNoTracking()
引起的。
我有这样的东西
var myObject = dbContext.GetRepo<myType>().Query().AsNoTracking().SingleOrDefault()
然后稍后我使用该对象设置另一个对象。
var myChild = new Child { parent = myObect }
很显然,EntityFramework试图创建一个全新的对象,因此会导致多重错误。