2

我们正在使用一个遗留数据库,我想知道我们的设置是否完全可以使用 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 的有效期是不相交的,因此在任何给定时间,Entity 和 EntityDef 之间应该存在一对一的关系。当尝试使用休眠来映射实体表时,问题就出现了。我们使用以下映射

<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>

当不同的休眠映射仅通过其 ID 引用具有多个 EntityDef 的实体时,就会出现问题。

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

Hibernate 通过其 ID 查询实体并抛出一个有意义的异常:

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?

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

谢谢!

4

1 回答 1

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 行)

于 2013-06-21T06:51:15.410 回答