我是 nHibernate 的新手,并试图了解从 Web 应用程序表单 POST 更新分离对象的正确方法。 (我们使用的是 ASP.NET MVC)
我要更新的对象包含(除其他外)子对象的 IList,映射如下:
<bag name="PlannedSlices" inverse="true" cascade="all-delete-orphan">
<key column="JobNumber" />
<one-to-many class="SliceClass" />
</bag>
我们已经安排了我们的 MVC 编辑 View 表单,以便当它被回发时,我们的操作方法被传递给一个对象(包括子项的 List<>。我们通过表单正确地往返所有实体 ID。
我们对 post 操作方法的天真尝试执行 session.SaveOrUpdate(parentObject),其 parentObject 已被默认模型绑定(bind)器从 View 表单中抓取。
这似乎适用于以下任何情况:
(查看 nHibernate 日志,我可以看到它正确地确定对象是新的还是现有的,并发出适当的 UPDATE 或 INSERT)
失败的场景是:
- 删除子对象 - 即如果它们不在 IList 中,它们不会从数据库中删除。没有异常(exception)或任何东西,它们只是不会被删除。
我的理解是,这是因为 nHibernate 执行创建需要删除的子列表的魔法不适用于分离实例。
我还没有找到一个简单的例子来说明这种 Action 方法在 nHibernate 中应该是什么样子(即使用模型绑定(bind)器对象作为分离的 nHibernate 实例) - 基于 MS EF 的示例(例如 http://stephenwalther.com/blog/archive/2009/02/27/chapter-5-understanding-models.aspx )似乎使用“ApplyPropertyChanges”方法将更改的属性从模型绑定(bind)对象复制到重新加载的实体实例。
所以,毕竟,问题很简单——如果我有模型绑定(bind)器给我一个包含子对象集合的新对象,我应该如何通过 nHibernate 更新它(其中“更新”可能包括删除子对象)?
最佳答案
这是一个我认为你正在尝试做的例子。如果我误解了您要执行的操作,请告诉我。
给定以下“域”类:
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:
删除ChildrenOfEvictedObject.CanDeleteChildren:通过
NHibernate: 插入 [Person] (Name, Id) VALUES (@p0, @p1); @p0 = '乔',@p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'
NHibernate: INSERT INTO [Pet] (Name, Id) VALUES (@p0, @p1); @p0 = '狗',@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb'
NHibernate: INSERT INTO [Pet] (Name, Id) VALUES (@p0, @p1); @p0 = '猫',@p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'
NHibernate: UPDATE [Pet] SET Person_id = @p0 WHERE Id = @p1; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2',@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb'
NHibernate: UPDATE [Pet] SET Person_id = @p0 WHERE Id = @p1; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2',@p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'
NHibernate: SELECT person0_.Id as Id5_0_, person0_.Name as Name5_0_ FROM [Person] person0_ WHERE person0_.Id=@p0; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'
NHibernate: SELECT pets0_.Person_id as Person3_1_, pets0_.Id as Id1_, pets0_.Id as Id6_0_, pets0_.Name as Name6_0_ FROM [Pet] pets0_ WHERE pets0_.Person_id=@p0; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'
NHibernate: UPDATE [Person] SET Name = @p0 WHERE Id = @p1; @p0 = '驱逐',@p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'
NHibernate: UPDATE [Pet] SET Name = @p0 WHERE Id = @p1; @p0 = '狗',@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb'
NHibernate: UPDATE [Pet] SET Person_id = null WHERE Person_id = @p0 AND Id = @p1; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2',@p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'
NHibernate:从 [Pet] 中删除 Id = @p0; @p0 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'
NHibernate: SELECT person0_.Id as Id5_0_, person0_.Name as Name5_0_ FROM [Person] person0_ WHERE person0_.Id=@p0; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'
NHibernate: SELECT pets0_.Person_id as Person3_1_, pets0_.Id as Id1_, pets0_.Id as Id6_0_, pets0_.Name as Name6_0_ FROM [Pet] pets0_ WHERE pets0_.Person_id=@p0; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'
注意从 [宠物] 中删除...
因此,您需要做的是使用修改后的集合手动休眠一个 Person 对象(在此示例中),它应该能够确定要删除的内容。确保您设置了 Cascade.AllDeleteOrphan() 属性。
关于asp.net-mvc - 从 asp.net POST 操作方法更新休眠实体的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/794314/