0

几天来我一直在寻找我的问题的答案,我已经尝试了大多数提示/答案,甚至查看了 nHibernate 生成的数百行日志,但我找不到让我的映射工作的方法.. nHiberante 在要求 SaveOrUpdate 时仍然拒绝生成任何删除语句。

我有三个独立的实体,Person、House 和 Room……实际上,每个 Person 将有一个房子,每个房子可以有多个房间,房子和房间之间的映射正如预期的那样是一对多的,我想要在 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();
        }
    }

House 类分别拥有两个 Person 和 Room 类型的列表,Person 和 Room 类都拥有对 House 对象的引用。

所以我创建了一个 House 的实例并设置了它的两个子列表 Person(one 1) 和 Room(multiple rooms),并将 Person/Rooms 的属性链接回 House..并使用 session.SaveOrUpdate 将 Person 全部保存效果很好。

然后我尝试检索 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 ...比根本不删除房间要好,但我真的希望它从中删除孤立的房间D B..

更新 2: session.Merge on Person 正在工作(SaveOrUpdate 没有)..虽然我不明白为什么..

4

1 回答 1

1

尝试将您的保存/更新包装在事务中:

using (ITransaction transaction = session.BeginTransaction())
{
    session.Save(SomeObject);
    transaction.Commit();
}
于 2013-05-08T14:11:09.000 回答