如何使用composite-id解决Session.get()奇怪的行为?

时间:2012-07-05 09:36:42

标签: java hibernate composite-id

我正在尝试为没有映射的复合标识符声明复合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 ,这实际上打破了很多现有代码。

我正在探索的事情是:

  1. 有没有办法使session.get()工作而不声明Id类(我知道这是一种沮丧的做法,但所需的更改量可能会令人望而却步)?
  2. 替代方法可以告诉hibernate像以前一样处理属性,而不添加id。在他们面前?
  3. 将hibernate升级到v4(因为依赖项目和审批流程而不容易)?
  4. 是否有其他选项/解决方法?
  5. 到目前为止,我只是设法使上述解决方案成功,但我正在寻找不那么具有干扰性的解决方案,并希望获得任何线索,建议和相关文档的指示。

2 个答案:

答案 0 :(得分:1)

您的第一个代码段中的wrapper是什么?如果它是一个附加实体(我怀疑它是),显然,session.get()将返回具有相同标识符的附加实体,并且由于标识符是实体本身,它将返回给定的附加实体。会话中始终只有一个给定实体的实例。

现在,回答你的问题:

  1. AFAIK,它按预期工作。
  2. 没有
  3. 这是一个问题吗?
  4. 最好的解决方法是做正确的事情并停止使用复合标识符。根据Hibernate的建议,使用单列自动生成的ID,一切都会简单得多。

答案 1 :(得分:0)

问题来自使用有意义的对象作为session.get()方法的id。

事实证明,session.get()有副作用并修改其参数(在PojoInstantiator.instantiate()内部发生)。在加载时,当hibernate检测到id类等于映射类时,它会跳过实例创建并使用传递给方法的id对象而不是实例化新实例。该对象通过数据库覆盖现有字段来提供水合作用。

解决方案是在没有键映射时,如果metadata.getIdentifier()返回对象,则复制对象。该克隆将被水合并由get()返回。