C# 是否可以级联.All(),删除除外?
我将分别获得一个对象列表(而不是从NHibernate获得),并将父对象IEnumerable设置为等于此返回对象。最初,我们只需要读取对象。然后,我们只需要更新父级上的特定字段。最近,我们需要更新孩子的字段。到目前为止,SaveOrUpdate()一切顺利。现在,我需要更新子对象,即使子对象集合附加到分离的父对象(不使用NHibernate)。下面的代码会更新父级,但不会更新子级。如果我全部执行,则如果父对象没有集合,则子对象将被删除。我不想这样做,因为我担心这种行为的遗留用途 期望的行为:C# 是否可以级联.All(),删除除外?,c#,nhibernate,nhibernate-mapping,C#,Nhibernate,Nhibernate Mapping,我将分别获得一个对象列表(而不是从NHibernate获得),并将父对象IEnumerable设置为等于此返回对象。最初,我们只需要读取对象。然后,我们只需要更新父级上的特定字段。最近,我们需要更新孩子的字段。到目前为止,SaveOrUpdate()一切顺利。现在,我需要更新子对象,即使子对象集合附加到分离的父对象(不使用NHibernate)。下面的代码会更新父级,但不会更新子级。如果我全部执行,则如果父对象没有集合,则子对象将被删除。我不想这样做,因为我担心这种行为的遗留用途 期望的行为:
1.级联对集合的任何更改(无论父集合中是否由NHibernate检索)。 2.即使父对象没有子对象集合,也不要删除对象 这可能吗 这是我们的NHibernate保存方法:
[Transaction]
public int? Save(DocumentFieldDTO entity, bool autoFlush)
{
var persisted = CurrentSession.Merge(entity);
entity.DocumentFieldID = persisted.DocumentFieldID;
if (autoFlush) { CurrentSession.Flush(); }
return entity.DocumentFieldID;
}
DocumentFieldDTOMap如下所示:
public class DocumentFieldDTOMap : EntityMapBase
{
public DocumentFieldDTOMap()
{
Table("DocumentField");
Id(m => m.DocumentFieldID).GeneratedBy.Increment().UnsavedValue(null);
Map(x => x.Name);
Map(x => x.DocumentSectionID).Not.Update();
// .... Lots of other fields ....//
HasMany(x => x.DocumentFieldOrgs)
.Cascade.SaveUpdate()
.LazyLoad()
.KeyColumn("DocumentFieldID");
}
}
}
如果我将Cascade.SaveUpdate()
更改为Cascade.All()
更新可以工作,但也会删除。我想消除删除功能
更新(1/27/2014):
我刚刚验证了当映射为SaveUpdate()
时,删除是级联的,因此这不是一个大问题,因为我没有更改现有的功能。我仍然希望能够更新除删除之外的所有级联。如果可能的话,一个解决方案将是未来的参考
更新(2/10/2014)
以下是验证级联为“SaveUpdate()”时是否删除子级的测试。GetDocumentFieldDTOWithADO(DocumentFieldID)
使用与NHibernate相同的事务,第一次调用(保存前)时有318个DocumentFieldOrg,保存后调用时有0个DocumentFieldOrg。也许考试有问题?它会因为我调用Merge而删除子级吗
[Test]
public void Save_ShouldDeleteDocumentFieldOrgs_WhenSavingDocumentFieldWithoutDocFieldOrgsList()
{
//arrange
var expectedDocField = GetDocumentFieldDTOWithADO(DocumentFieldID);
expectedDocField.DocumentFieldOrgs = null;
//act
Repository.Save(expectedDocField, false);
SessionFactory.GetCurrentSession().FlushAndEvict(expectedDocField);
//assert
var actualDocField = GetDocumentFieldDTOWithADO(DocumentFieldID);
actualDocField.DocumentFieldOrgs.Should()
.BeEmpty("DocumentFieldOrgs should be deleted if the parent does not have a child collection");
}
更新(2014年2月11日)-Radim在下面的回答中是正确的。NHibernate没有删除这些孩子。它将它们与父项解除关联。更新,反映查询更改 您在查询更新中显示的测试已经证明: 如果
parent.Children
设置为null
并被分配,则它将没有子级-下次访问
让我解释一下发生了什么,让我使用一些虚拟语言(请注意,我正在使用家长
和孩子
来简化)
1) 父子对象的映射是cascade=“save update”
这是NHibernate的一条信息,在创建或修改过程中,应将Save()或Update()调用传递给子集合 2) 让我们加载父对象
var session = ... // get a ISession for our test
var parent = session.Get<Parent>(1); // e.g. DocumentFieldDTO
// NOT Empty -- is true: IsNotEmpty()
Assert.IsTrue(parent.Children.IsNotEmpty()); // e.g. DocumentFieldOrgs
以下是执行的SQL语句:
exec sp_executesql N'UPDATE [schema].[Child_Table]
SET ParentId = null WHERE ParentId = @p0',N'@p0 int',@p0=1
正如我们所看到的,由于映射save update
,NHibernate确实通过删除引用来处理这个场景。实际上,通过更新子表
4) 再次加载父级
parent = session.Get<Parent>(1);
// EMPTY -- is true: IsEmpty()
Assert.IsTrue(parent.Children.IsEmpty());
parent=session.Get(1);
//EMPTY——为true:IsEmpty()
Assert.IsTrue(parent.Children.IsEmpty());
总结:
正如我们在上面看到的,NHibernate正在做映射和预期的事情。没有删除。只是更新,删除引用
这个答案的前一部分
答案是:更改您的public int?保存(…)
实现。NHibernate级联按预期工作,请在此处阅读更多内容
首先看一下上面的陈述:
期望的行为:1) 级联对集合的任何更改(无论父集合中是否由NHibernate检索)。
2) 即使父对象没有子对象的集合,也不要删除对象 粗体部分是
级联概念
不起作用的原因。因为:
只有在现有的父级被级联/重复/传递
现有/已知的子项(子项) NHiberante级联实现实际上是这样工作的:(摘录) 映射。。。with
cascade=“all”
将关联标记为父/子样式的关系,其中父项的保存/更新/删除将导致子项(ren)的保存/更新/删除未被其父级引用的子级不会自动删除,但使用cascade=“all delete orphan”映射的关联除外
不仅如此,它还没有被删除。如果未引用,则不会接收任何类型的级联操作的触发器
建议:
调整Save()
方法,以执行两个操作:
session.Flush()
。ISession引用的对象上的任何更改都将被持久化我不明白你的回答。如果父POCO对象没有任何子POCO对象,NHibernate将从数据库中删除子记录。我可以在save实现中实现子项的更改管理,但我希望NHibernate处理对象映射和更改管理。我想我希望有一些映射或SaveUpdate/Merge方法的实现,可以指示NHibernate更新记录,但永远不要删除对象。你可以很好地控制你可以更新什么,但不能控制删除什么。也许我不理解你的问题。级联是这样工作的:1)必须有传递给会话的父级(SaveOrUpdate(parent)2)任何子级都将按此处所述进行级联。3) 如果出现
save udpate
delete,将永远不会发出。4) 在“全部”的情况下,将删除
parent = session.Get<Parent>(1);
// EMPTY -- is true: IsEmpty()
Assert.IsTrue(parent.Children.IsEmpty());