我已经在几天内搜索了我的问题的答案,我已经尝试了大部分提示/答案,甚至查看了nHibernate生成的数百行日志,但我找不到办法获取我的映射工作..当被要求SaveOrUpdate时,nHiberante仍然拒绝生成任何删除语句。
我有三个独立的实体,人物,房子和房间...真实的话,每个人都有一个房子,每个房子可以有多个房间,房子和房间之间的映射是一对多的预期我希望在Person和House之间进行一对一的映射,然后我在流畅的nHibernate wiki上阅读,它说它实际上是一个很多(人)到一个(房子),因为在数据库级别没有什么可以阻止多个人共享同一所房子。我想这是有道理的,所以我的数据库架构和类映射设计如下:
CREATE TABLE [dbo].[Person](
[PersonId] [int] IDENTITY(1,1) NOT NULL,
[HouseId] [int] NOT NULL
)
CREATE TABLE [dbo].[House](
[HouseId] [int] IDENTITY(1,1) NOT NULL,
[HouseName] [varchar](500) NOT NULL
)
CREATE TABLE [dbo].[Room](
[RoomId] [int] IDENTITY(1,1) NOT NULL,
[HouseId] [int] NOT NULL
)
HouseId on [Person] and [Room] are both foreign keys referencing HouseId from [House] table
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Table("Person")
Id (x=>x.Id).Column("PersonId").GeneratedBy.Identity().UnsavedValue(0);
Reference(x=>x.House).Column("HouseId").ForeignKey("HouseId").Not.LazyLoad().Cascade.All();
}
}
public class HouseMap : HouseMap<Room>
{
public RoomMap()
{
Table("House")
Id (x=>x.Id).Column("HouseId").GeneratedBy.Identity().UnsavedValue(0);
HasMany(x => x.Persons)
.KeyColumn("HouseId")
.Not.LazyLoad()
.Cascade.AllDeleteOrphan().Inverse();
HasMany(x => x.Rooms)
.KeyColumn("HouseId")
.Not.LazyLoad()
.Cascade.AllDeleteOrphan().Inverse();
}
}
public class RoomMap : ClassMap<Room>
{
public RoomMap()
{
Table("Room")
Id (x=>x.Id).Column("RoomId").GeneratedBy.Identity().UnsavedValue(0);
Reference(x=>x.House).Column("HouseId").ForeignKey("HouseId").Not.LazyLoad().Cascade.All();
}
}
Class House分别拥有两个Person和Room类型的列表,Person和Room类都拥有一个返回House对象的引用。
所以我创建了一个House的实例并设置了它的两个子列表Person(一个1)和Room(多个房间),并且还将Person / Rooms的属性链接回House ..并使用session.SaveOrUpdate来保存一切都很好的人。
然后我尝试检索Person的实例,并从Person.House.List中删除一个房间并将room.House设置为null以完全中断引用,然后使用session.SaveOrUpdate再次保存Person(让我们称之为Person) A),,, nHibernate正确生成删除语句,删除没有链接到其父House的孤儿房间......到目前为止一直这么好......
这是我的问题开始...在我的应用程序中,我需要将对象Person转换为PersonContract,然后将其发送到客户端,客户端能够从PersonContract.HouseContract中删除roomContract并发送一个PersonContract的副本。请注意,在PersonContract中,没有双边引用,即PersonContract具有HouseContract的一个属性,而HouseContract仅包含RoomContract列表,因此HouseContract不保留PersonContract列表,而RoomContract没有HouseContract属性。
然后在服务器端,我将PersonContract转换回Person对象,转换器负责创建Person,Room和house的所有新实例,并设置它们的ID并在它们之间构建所有双边引用。
问题是......当我在Person对象上使用session.SaveOrUpdate时(合同转换后),nHibernate似乎忽略了一个房间已从集合中删除但它更新或插入作业的事实。
我仔细检查了我的合同转换器,以确保所有属性/引用/ ID都已正确设置,并且它看起来与上面的人A完全相同...但我不明白为什么nHibernate没有做这里的工作。
我在Person / Room / House上覆盖了Equals和GetHashCode以返回其id。
我观察到的另一个事实是,当我在转换后的Person对象上使用session.SaveOrUpdate时,nHibernate生成了大量的Update语句,即使该值没有真正改变,看起来好像nHibernate不知道状态持久化的Person对象,所以选择通过使用Id ...
识别它来更新所有内容我对nHibernate很新...所以如果我在这里做了一些可怕的错误,请告诉我:))
更新:如果我从House和Room之间的一对多映射中删除Inverse,那么nHibernate会将删除的Room的房屋ID设置为NULL ...比根本不删除房间更好但我真的希望它从DB中移除孤儿房间。
更新2 :Person.Merge on Person正在运行(SaveOrUpdate没有)....虽然我不明白为什么...
答案 0 :(得分:1)
尝试在事务中包装保存/更新:
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(SomeObject);
transaction.Commit();
}