Java 如何使用复合id解决Session.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

我正在尝试对声明复合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>
代理密钥被定义为具有两个字段和所需的equals/hashcode的对象。
使用元数据返回的此更改id。getIdentifier()是代理密钥的实例,session.get()从数据库中获取对象(如果存在)

映射修复的问题是,条件和HQL的属性名称从identifier更改为id.identifier,这实际上破坏了许多现有代码

我目前正在探索的是:

  • 有没有一种方法可以使session.get()在不声明Id类的情况下工作(我知道这是一种不鼓励的做法,但所需的更改量可能会很高)
  • 另一种方法是告诉hibernate像以前一样处理属性,而不在属性前面添加id吗
  • 将hibernate升级到v4(不容易,因为依赖项目和审批流程)
  • 还有其他可用的选项/解决方法吗

  • 到目前为止,我只设法使上述解决方案起作用,但我正在寻找干扰性较小的解决方案,希望您能提供任何线索、建议和相关文档的指针。

    您的第一个代码片段中的
    包装器是什么?如果它是一个附加实体(我怀疑它是),显然,
    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>