Java 如何使用复合id解决Session.get()的奇怪行为?
我正在尝试对声明复合id但没有映射复合标识符的对象的会话执行get。Java 如何使用复合id解决Session.get()的奇怪行为?,java,hibernate,composite-id,Java,Hibernate,Composite Id,我正在尝试对声明复合id但没有映射复合标识符的对象的会话执行get。 使用的Hibernate版本是3.5.5 提取代码是通用代码,用于读取包装实际数据的容器对象: ClassMetadata metadata = session.getSessionFactory().getClassMetadata(wrapper.getDomainClass()); Serializable id = metadata.getIdentifier(wrapper, EntityMod
使用的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>
代理密钥被定义为具有两个字段和所需的equals/hashcode的对象。使用元数据返回的此更改id。getIdentifier()是代理密钥的实例,session.get()从数据库中获取对象(如果存在) 映射修复的问题是,条件和HQL的属性名称从identifier更改为id.identifier,这实际上破坏了许多现有代码 我目前正在探索的是:
到目前为止,我只设法使上述解决方案起作用,但我正在寻找干扰性较小的解决方案,希望您能提供任何线索、建议和相关文档的指针。您的第一个代码片段中的
包装器是什么?如果它是一个附加实体(我怀疑它是),显然,session.get()
将返回具有相同标识符的附加实体,并且由于标识符是实体本身,它将返回给定的附加实体。会话中任何给定实体始终只有一个实例
现在,回答您的问题:
好了,它按预期工作
没有
这是一个问题吗
最好的解决方法是做正确的事情,停止使用复合标识符。按照Hibernate的建议,使用单列自动生成的ID,一切都会简单得多
问题来自于使用有意义的对象作为session.get()方法的id
事实证明session.get()有副作用并修改了它的参数(发生在PojoInstantiator.instantiate()的深处)。加载时,当hibernate检测到id类等于映射类时,它将跳过实例创建,并使用传递给方法的id对象,而不是实例化新实例。此对象是由数据库覆盖现有字段而生成的
解决方案是,如果metadata.getIdentifier()在未映射任何键时返回对象,则克隆对象。该克隆将被水合并由get()返回。在get完成时,包装器未连接到会话。它至少有一个我们要替换的对象键。以前的版本可以在数据库中,也可以保存在同一会话中。这是一个批量保存/更新过程,自动生成的id不是选项,因为id是由外部系统生成的。如果我们使用它们,那么我们将不得不切换到执行查询并批量手动关联对象。如果1仅适用于连接的实体,但适用于分离的实体,则它看起来不正确,并且映射键和非映射键的行为不同。使用注释,您可以通过将实体的多个字段映射为@Id,并指定具有相同属性名称和类型的Id类,来完成第二个问题中所需的操作。我不知道用XML映射是否可行。我已经更新了最初的帖子并发布了一个解决方案。我现在觉得它像一只冬眠的虫子。会话没有考虑实例化器行为的某些方面。
<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>