我刚开始接触nHibernate,并试图找到正确的方法来更新web应用程序表单帖子中分离的对象。(我们使用的是ASP.NET MVC)
我试图更新的对象包含(除其他外)子对象的IList,映射如下所示:
<bag name="PlannedSlices" inverse="true" cascade="all-delete-orphan">
<key column="JobNumber" />
<one-to-many class="SliceClass" />
</bag>
我们已经安排了MVC编辑视图表单,以便当它回发时,我们的操作方法被传递给am对象(包括子项的List<> )。我们通过表单正确地进行了所有实体ID的往返。
我们对post操作方法的天真尝试使用了一个session.SaveOrUpdate( parentObject ),它使用默认的模型绑定器从视图表单中刮过的parentObject。
对于下列任何一种场景,这似乎都很好:
创建一个新父object
失败的情况是:-删除子对象-也就是说,如果它们不在IList中,则不会从数据库中删除它们。没有例外或任何事,他们只是没有被删除。
我的理解是,这是因为nHibernate创建一个需要删除的子列表的魔力并不适用于分离的实例。
我还没有找到一个简单的示例,说明这种操作方法在nHibernate中应该是什么样子(即使用模型绑定对象作为独立的nHibernate实例)--基于MS (例如http://stephenwalther.com/blog/archive/2009/02/27/chapter-5-understanding-models.aspx)的示例似乎使用'ApplyPropertyChanges‘方法将更改的属性从模型绑定对象复制到重新加载的实体实例。
因此,毕竟,问题很简单--如果我有模型绑定器给我一个包含子对象集合的新对象,我应该如何通过nHibernate更新它(其中“更新”可能包括删除子对象)?
发布于 2009-04-27 11:50:07
这是一个我认为你想做的事情的例子。如果我误解了你想做的事,请告诉我。
给定以下“域”类:
public class Person
{
private IList<Pet> pets;
protected Person()
{ }
public Person(string name)
{
Name = name;
pets = new List<Pet>();
}
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IEnumerable<Pet> Pets
{
get { return pets; }
}
public virtual void AddPet(Pet pet)
{
pets.Add(pet);
}
public virtual void RemovePet(Pet pet)
{
pets.Remove(pet);
}
}
public class Pet
{
protected Pet()
{ }
public Pet(string name)
{
Name = name;
}
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}
通过以下映射:
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
LazyLoad();
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Name);
HasMany(x => x.Pets)
.Cascade.AllDeleteOrphan()
.Access.AsLowerCaseField()
.SetAttribute("lazy", "false");
}
}
public class PetMap : ClassMap<Pet>
{
public PetMap()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Name);
}
}
这个测试:
[Test]
public void CanDeleteChildren()
{
Person person = new Person("joe");
Pet dog = new Pet("dog");
Pet cat = new Pet("cat");
person.AddPet(dog);
person.AddPet(cat);
Repository.Save(person);
UnitOfWork.Commit();
CreateSession();
UnitOfWork.BeginTransaction();
Person retrievedPerson = Repository.Get<Person>(person.Id);
Repository.Evict(retrievedPerson);
retrievedPerson.Name = "Evicted";
Assert.AreEqual(2, retrievedPerson.Pets.Count());
retrievedPerson.RemovePet(retrievedPerson.Pets.First());
Assert.AreEqual(1, retrievedPerson.Pets.Count());
Repository.Save(retrievedPerson);
UnitOfWork.Commit();
CreateSession();
UnitOfWork.BeginTransaction();
retrievedPerson = Repository.Get<Person>(person.Id);
Assert.AreEqual(1, retrievedPerson.Pets.Count());
}
运行并生成以下sql:
DeletingChildrenOfEvictedObject.CanDeleteChildren :传递NHibernate:插入Person值( @p0,@p1);@p0= 'joe',@p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2‘
NHibernate:插入Pet值( @p0,@p1);@p0=“Pet”,@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb‘
NHibernate:插入Pet值( @p0,@p1);@p0= 'cat',@p1 =‘010c2fd9-59c4-94fb-9bf801013abb’
NHibernate:更新Pet Person_id = @p0,其中Id = @p1;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2',@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb‘
NHibernate:更新Pet Person_id = @p0,其中Id = @p1;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2',@p1 =‘01010c2fd9-59c4-59c4-94fb-9bff801013abb’
NHibernate:选择person0_.Id作为Id5__,从Person person0_中选择person0_.Name作为person0_.Id=@p0;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2‘
NHibernate:选择pets0_.Person_id作为Person3_1_,pets0_.Id作为Id1_,pets0_.Id作为Id6__,pets0_.Name作为Name6__从宠物pets0_ pets0_.Person_id=@p0;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2‘
NHibernate:更新个人设置名称= @p0,其中Id = @p1;@p0 =“逐出”,@p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2‘
NHibernate:更新宠物集名称= @p0,其中Id = @p1;@p0 =‘d1’,@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb‘NHibernate: Person_id = null,其中Person_id = @p0,Id = @p1;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2',@p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb’
NHibernate:从宠物中删除Id = @p0;@p0 = '010c2fd9-59c4-4e66-94fb-9bf801013abb‘
NHibernate:选择person0_.Id作为Id5__,从Person person0_中选择person0_.Name作为person0_.Id=@p0;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2‘
NHibernate:选择pets0_.Person_id作为Person3_1_,pets0_.Id作为Id1_,pets0_.Id作为Id6__,pets0_.Name作为Name6__从宠物pets0_ pets0_.Person_id=@p0;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2‘
注意从宠物中删除..。
因此,您需要做的是将修改过的集合传递给一个Person对象(在本例中),它应该能够决定要删除什么。确保设置了Cascade.AllDeleteOrphan()属性。
发布于 2009-04-27 12:44:47
Rob的回答说服我更仔细地研究‘将现有项加载到新会话中,然后合并’的方法,当然还有ISession.Merge,它似乎完全符合我的要求,即获取一个新的对象,并将其与刚刚重新加载到第二次会话的前一个对象合并。
因此,我认为我试图问的问题的答案是“重新加载现有实体,然后用新实体调用'ISession.Merge‘。”
https://stackoverflow.com/questions/794314
复制相似问题