Nhibernate 更改集合属性会导致更新未触及的记录
我有三张桌子:Person、Role和PersonRole。角色表中的记录很少更改,因此我决定将角色表添加到NHibernate的二级缓存中。现在有几项测试失败了,他们说:Nhibernate 更改集合属性会导致更新未触及的记录,nhibernate,Nhibernate,我有三张桌子:Person、Role和PersonRole。角色表中的记录很少更改,因此我决定将角色表添加到NHibernate的二级缓存中。现在有几项测试失败了,他们说: ReadOnlyCache: Can't write to a readonly object ShipRepDAL.ShipRepDTO.Role 问题: 应用程序不应更新角色记录。我的代码只涉及角色对象上的PersonRole集合,因此我不理解Nhibernate为什么要更新角色记录 下面是从业务对象到个人实体的代码
ReadOnlyCache: Can't write to a readonly object ShipRepDAL.ShipRepDTO.Role
问题:
应用程序不应更新角色记录。我的代码只涉及角色对象上的PersonRole集合,因此我不理解Nhibernate为什么要更新角色记录
下面是从业务对象到个人实体的代码映射示例。此示例添加了一个新角色:
[...]
var pr = new PersonRole
{
Person = person,
Role = role
};
person.PersonRoles.Add(pr);
role.PersonRoles.Add(pr); //If I comment out this line, it works - but then the Session will be out of sync
[...]
new PersonService().SaveOrUpdate(person); //Flush
下面是每个表的映射示例:
人
[...]
[...]
角色
[...]
[...]
角色
[...]
[...]
[...]
任何关于错误的提示都将不胜感激 TL;博士
我看不出您遇到麻烦的明确原因,除了您应该在映射中将bag
替换为set
之外
细节
bag
有一个奇怪的用法,在您的情况下应该正常设置set
。还是我遗漏了什么
一个包有一个非常特殊的语义,如果像你这样使用它会导致NHibernate在每次PersonRole
更改时都会触及你的角色,我不会感到惊讶
见§6.2结尾处:
一个包是一个无序的、未编制索引的集合,可能多次包含同一元素
您的PersonRole
集合在Role
或Person
上是否真的包含重复的PersonRole
此外,有些线路仍然是关于行李的:
NHibernate无法单独创建、删除或更新行,因为没有可用于标识单个行的键
由于您的行李收集不是真正的一个,您在PersonRole
和Role
之间没有中间表来存放您的行李(在bag
mapping上没有table
属性),在这种情况下,我想这就是Role
,它最终被用作行李表,因此,当您更改PersonRoles
collection时,会导致NHibernate触摸它
更多详情见§19.5.1末尾:
袋子是最坏的情况。由于包允许重复的元素值,并且没有索引列,因此不能定义主键。NHibernate无法区分重复行。NHibernate通过完全删除(在一次删除中)并在集合发生更改时重新创建集合来解决此问题。这可能是非常低效的
TL;博士
我看不出您遇到麻烦的明确原因,除了您应该在映射中将bag
替换为set
之外
细节
bag
有一个奇怪的用法,在您的情况下应该正常设置set
。还是我遗漏了什么
一个包有一个非常特殊的语义,如果像你这样使用它会导致NHibernate在每次PersonRole
更改时都会触及你的角色,我不会感到惊讶
见§6.2结尾处:
一个包是一个无序的、未编制索引的集合,可能多次包含同一元素
您的PersonRole
集合在Role
或Person
上是否真的包含重复的PersonRole
此外,有些线路仍然是关于行李的:
NHibernate无法单独创建、删除或更新行,因为没有可用于标识单个行的键
由于您的行李收集不是真正的一个,您在PersonRole
和Role
之间没有中间表来存放您的行李(在bag
mapping上没有table
属性),在这种情况下,我想这就是Role
,它最终被用作行李表,因此,当您更改PersonRoles
collection时,会导致NHibernate触摸它
更多详情见§19.5.1末尾:
袋子是最坏的情况。由于包允许重复的元素值,并且没有索引列,因此不能定义主键。NHibernate无法区分重复行。NHibernate通过完全删除(在一次删除中)并在集合发生更改时重新创建集合来解决此问题。这可能是非常低效的
经过进一步调查,根本原因是一个拦截器。此处发布了一个新问题:
我仍然想继续回答这个问题,因为弗雷德里克的回答很有趣。经过进一步调查,根本原因是一个拦截器。此处发布了一个新问题:
我仍然想继续回答这个问题,因为弗里德里克的回答很有趣。谢谢你的回答!我怀疑bag vs set是个问题,但我会记住bag对性能的影响。看看我的编辑,我相信拦截者是罪魁祸首。谢谢你的回复!我怀疑bag vs set是个问题,但我会记住bag对性能的影响。看看我的编辑,我相信拦截者是罪魁祸首。你的问题现在完全不同了。通过问一个新问题而不是编辑这个问题,你会有更多的机会得到答案。因此,最好将此版本还原为其原始版本,并提出另一个问题。(你也可以考虑将初始问题的实际原因(拦截器)添加到这里作为答案,或者如果你觉得这是一个太窄的情况,删除整个事件。)是的,你是对的。我恢复到原来的版本,并在下面的回答中添加了一个指向新问题的链接。我仍然想继续提问,因为你的回答很有趣。你的问题现在完全不同了。通过问一个新问题,你会有更多的机会得到答案
<class name="Person" select-before-update="true" optimistic-lock="version" batch-size="25">
[...]
<version name="ModifiedDate" type="Timestamp" generated="always" />
[...]
<bag name="PersonRoles" inverse="true" cascade="all-delete-orphan">
<key column="PersonID"/>
<one-to-many class="PersonRole" />
</bag>
</class>
<class name="PersonRole" select-before-update="true" optimistic-lock="version" batch-size="25">
[...]
<version name="ModifiedDate" type="Timestamp" generated="always" />
[...]
<many-to-one name="Person" column="PersonID" />
<many-to-one name="Role" column="RoleID" />
</class>
<class name="Role" select-before-update="true" optimistic-lock="version" batch-size="25">
[...]
<version name="ModifiedDate" type="Timestamp" generated="always" />
[...]
<bag name="PersonRoles" inverse="true">
<key column="RoleID"/>
<one-to-many class="PersonRole" />
</bag>
[...]
</class>