我们正在使用遗留数据库,我想知道我们的设置是否完全符合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?
有许多业务逻辑期望类别等成为实体的一部分,因此如果我们不必诉诸于一对多的关系,那将是非常好的。
谢谢!
答案 0 :(得分:0)
我想说,这是你的建议和过滤技术的结合
<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行)