我正在尝试为没有映射的复合标识符声明复合id的对象执行get会话 使用的Hibernate版本是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中传递的相同的对象(不是相同的对象,而是对象的相同实例)。
Upd:实际上,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被定义为具有两个字段的对象,并且根据需要等于/ hashcode 使用此更改,metadata.getIdentifier()返回的id是SurrogateKey的实例,session.get()从数据库中获取对象(如果存在)。
映射修复的问题是标准和HQL的属性名称从标识符更改为 id.identifier ,这实际上打破了很多现有代码。
我正在探索的事情是:
到目前为止,我只是设法使上述解决方案成功,但我正在寻找不那么具有干扰性的解决方案,并希望获得任何线索,建议和相关文档的指示。
答案 0 :(得分:1)
您的第一个代码段中的wrapper
是什么?如果它是一个附加实体(我怀疑它是),显然,session.get()
将返回具有相同标识符的附加实体,并且由于标识符是实体本身,它将返回给定的附加实体。会话中始终只有一个给定实体的实例。
现在,回答你的问题:
答案 1 :(得分:0)
问题来自使用有意义的对象作为session.get()方法的id。
事实证明,session.get()有副作用并修改其参数(在PojoInstantiator.instantiate()内部发生)。在加载时,当hibernate检测到id类等于映射类时,它会跳过实例创建并使用传递给方法的id对象而不是实例化新实例。该对象通过数据库覆盖现有字段来提供水合作用。
解决方案是在没有键映射时,如果metadata.getIdentifier()返回对象,则复制对象。该克隆将被水合并由get()返回。