我正在尝试在没有映射复合标识符的情况下声明复合 id 的对象的会话上执行获取。
使用的休眠版本是 3.5.5。
获取代码是通用的,并读取包装实际数据的容器对象:
ClassMetadata metadata =
session.getSessionFactory().getClassMetadata(wrapper.getDomainClass());
Serializable id = metadata.getIdentifier(wrapper, EntityMode.POJO);
return session.get(wrapper.getDomainClass(), id, LockOptions.UPGRADE);
代码对实际映射一无所知,因此它必须查阅有关 id 的元数据。
如果映射定义如下:
<hibernate-mapping default-access="field">
<class name="Wrapper"
entity-name="Data"
table="DATA">
<composite-id>
<key-property name="identifier" column="identifier" />
<key-property name="version" column="version" />
</composite-id>
<component name="domainObject" class="Data">
<property name="source" column="source" />
</component>
</class>
</hibernate-mapping>
没有复合标识符类,id 等于对象本身并且等于包装器引用。
当我执行 session.get() 而不是从数据库中获取对象时,它返回与传入 id 的对象相同的对象(不是相等的对象,而是对象的相同实例)。
更新:实际上 session.get() 从数据库中加载对象,in
传递的 id 对象并将其返回。我监督最初认为它跳过加载。
到目前为止我发现的解决方案是引入映射的复合标识符并将映射更改为:
<hibernate-mapping default-access="field">
<class name="Wrapper"
entity-name="Data1"
table="DATA_1">
<composite-id class="SurrogateKey" mapped="true">
<key-property name="identifier" column="identifier" />
<key-property name="version" column="version" />
</composite-id>
<component name="domainObject" class="Data">
<property name="source" column="source" />
</component>
</class>
</hibernate-mapping>
SurrogateKey 被定义为具有两个字段和根据需要的等于/哈希码的对象。
通过 metadata.getIdentifier() 返回的更改 id 是 SurrogateKey 的一个实例,并且 session.get() 从数据库中获取对象(如果存在)。
映射修复的问题是标准和 HQL 的属性名称从标识符更改为id.identifier,这实际上破坏了许多现有代码。
我目前正在探索的事情是:
- 有没有办法在不声明 Id 类的情况下使 session.get() 工作(我知道这是一种不鼓励的做法,但所需的更改量可能会令人望而却步)?
- 替代方案是否可以告诉hibernate像以前一样对待属性,而不添加id。在他们面前?
- 将hibernate升级到v4(由于依赖项目和审批流程并不容易)?
- 还有其他可用的选项/解决方法吗?
到目前为止,我只设法使上述解决方案起作用,但我正在寻找侵入性较小的解决方案,并且希望能提供任何线索、建议和指向相关文档的指针。