我有三个表:Person,Role和PersonRole。 Role表中的记录很少更改,因此我决定将Role表添加到NHibernate的二级缓存中。现在有几个测试失败了,说:
ReadOnlyCache: Can't write to a readonly object ShipRepDAL.ShipRepDTO.Role
问题: 应用程序不应更新角色记录。我的代码只触及Role对象上的PersonRole集合,所以我不明白为什么Nhibernate正在更新Role记录。
以下是从业务对象到Person实体的代码映射示例。该示例添加了一个新角色:
[...]
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
以下是每个表格映射的示例:
人
<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>
PersonRole
<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>
非常感谢任何关于错误的指示!
答案 0 :(得分:1)
除非您在映射中将bag
替换为set
,否则我没有明确说明您遇到麻烦的原因。
bag
有一种奇怪的用法,在您的情况下通常应为set
。或者我错过了什么?
一个包具有非常特殊的语义,如果使用它会让我感到惊讶,因为NHibernate会在每次PersonRole
更改时触及你的角色。
见NHibernate reference,接近§6.2的结尾:
行李是无序的,无索引的集合,可能多次包含相同的元素。
您PersonRoles
或Role
上的Person
个馆藏可能包含重复的PersonRole
吗?
而且,有些线路仍然是关于袋子的:
NHibernate无法单独创建,删除或更新行,因为没有可用于标识单个行的键。
由于你的行李集合不是真的,你在PersonRole
和Role
之间没有中间表来保存行李(table
映射没有bag
属性),在这种情况下,我猜是Role
最终被用作包表,从而导致NHibernate在您更改PersonRoles
集合时触摸它。
Improving performances中的更多细节,接近§19.5.1的结尾:
袋子是最糟糕的情况。由于包允许重复的元素值并且没有索引列,因此不能定义主键。 NHibernate无法区分重复的行。 NHibernate通过完全删除(在单个DELETE中)并在每次更改时重新创建集合来解决此问题。这可能效率很低。
答案 1 :(得分:1)
经过进一步调查后,根本原因是拦截器。此处发布了一个新问题:Mask properties from dirty check
我还是想保留这个问题,因为弗雷德里克的答案很有趣。