hibernate非唯一的一对一映射

时间:2013-06-20 19:28:06

标签: hibernate java-ee hibernate-mapping

我们正在使用遗留数据库,我想知道我们的设置是否完全符合Hibernate:

我们有两个表Entity和EntityDef

CREATE TABLE entity
( 
  id DOUBLE,
  name VARCHAR(20),
  PRIMARY KEY (id)
)

CREATE TABLE entitydef 
( 
  id DOUBLE,
  effectivedate DATE,
  terminationdate DATE,
  category VARCHAR(20),

  PRIMARY KEY (id, terminationdate)
)

基本上对于每个实体,它可以有多个相应的EntityDef,用于指定特定有效期的参数。这些EntityDef的有效期是不相交的,因此在任何给定时间,实体和EntityDef之间应该存在一对一的关系。尝试使用hibernate映射Entity表时出现问题。我们使用以下映射

<class name="com.company.Entity" table="Entity">
    <cache usage="read-write" />
    <id name="id" type="long">
        <column name="id" />
    </id>
    <property name="name" type="string">
        <column name="name" />
    </property>
    <join table="entitydef">
        <key>
            <column name="id" sql-type="long />
        </key>
        <property name="category" type="string">
            <column name="category" />
        </property>
    </join>
</class>

<class name="com.company.EntityDef" table="entitydef">
    <cache usage="read-write" />
    <composite-id>
        <key-property name="id" type="long">
            <column name="id" />
        </key-property>
        <key-property name="terminationDate" type="com.company.time.hibernate.Date">
            <column name="terminationdate" />
        </key-property>
    </composite-id>
    <property name="category">
        <column name="category" />
    </property>
</class>

当另一个hibernate映射仅通过其ID引用具有多个EntityDefs的实体时,就会出现问题。

...
<many-to-one name="entity" class="com.company.Entity" lazy="false">
    <column name="entityid" />
</many-to-one>
...

Hibernate通过ID对Entity进行查询,并抛出一个有意义的异常:

org.hibernate.HibernateException: More than one row with the given identifier was found: 1, for class: com.company.Entity

我们尝试在EntityDef映射中添加一个过滤器,如Hibernate文档中所示:

<filter-def name="effectiveDate">
    <filter-param name="asOfDate" type="date" />
</filter-def>   
<class name="com.company.EntityDef" table="entitydef">
    <cache usage="read-write" />
    <composite-id>
        <key-property name="id" type="long">
            <column name="id" />
        </key-property>
        <key-property name="terminationDate" type="com.company.time.hibernate.Date">
            <column name="terminationdate" />
        </key-property>
    </composite-id>
    <property name="category">
        <column name="category" />
    </property>
    <filter name="effectiveDate" condition=":asOfDate BETWEEN effectivedate and terminationdate" />
</class>

并在我们的查询中添加了以下代码:

sess.enableFilter("effectiveDate").setParameter("asOfDate", new Date());

但这似乎并没有影响任何事情。

我的问题是:这个设置是否可行,是否有一种方法可以与EntityDef表连接而无需明确指定终止日期?如果不是最好的解决方案?创建一对多关系并使用Entity类中的逻辑从集合中获取正确的EntityDef?

有许多业务逻辑期望类别等成为实体的一部分,因此如果我们不必诉诸于一对多的关系,那将是非常好的。

谢谢!

1 个答案:

答案 0 :(得分:0)

我想说,这是你的建议和过滤技术的结合

  • 创建一对多关系并使用Entity类中的逻辑从集合中获取正确的EntityDef
  • 使用<filter>

可以胜任。

不是映射已加入的类实体,而是让Entity的集合为EntityDef。所以,而不是映射

<join table="entitydef">

使用带过滤器的集合映射:

<set name="entityDefs" inverse="true">
  <key column="id"/>
  <one-to-many class="com.company.EntityDef"/>
  <filter name="effectiveDate" condition=":asOfDate BETWEEN effectivedate and terminationdate" />
</set>

如果(如问题所述),总是one-to-one映射到给定时间,我们需要将过滤器注入会话sess.enableFilter("effectiveDate")...(例如一些AOP)可以肯定)

现在,我们始终拥有包含完全一个项的EntityDefs集合。因此,我们可以使用entity.category访问器中的第一条记录隐藏操作。

我们正在使用它。在Entity创建时需要更多逻辑,但最后它还支持对EntityDef的投影(不影响分页,感谢过滤器总是返回1行)