【发布时间】:2011-06-26 15:50:17
【问题描述】:
我很难对包含基元映射 (Map
这里是实体(缩写):
@Entity(name = "ZPrincipal")
@Table(name = "users")
public class ZPrincipal implements Principal, Serializable {
@Id
@Column(name = "username")
private String username;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "user_metadata", joinColumns = { @JoinColumn(name = "username") })
@MapKeyColumn(name = "meta_key")
@Column(name = "meta_value", nullable = false)
private Map<String, String> metadata;
}
如您所见,有一个包含 Map 的用户类(ZPrincipal)。我的表格看起来像这样(同样,从“用户”中缩写一些字段,例如电子邮件、密码等):
CREATE TABLE users (
username VARCHAR(60) NOT NULL,
PRIMARY KEY (username)
);
CREATE TABLE user_metadata (
username VARCHAR(60) NOT NULL,
meta_key VARCHAR(255) NOT NULL,
meta_value VARCHAR(1024) NOT NULL,
CONSTRAINT user_meta_fk FOREIGN KEY (username) REFERENCES users (username),
PRIMARY KEY (username, meta_key)
);
一些示例内容:
用户表:
|username |
+---------+
|admin |
|brett |
+---------+
元数据表:
|username |meta_key |meta_value |
+---------+----------+------------+
|brett |key1 |value1 |
|brett |key2 |value2 |
+---------+----------+------------+
通过上述映射,当我使用 Hibernate 检索 ZPrincipal 列表时,如下所示:
Criteria criteria = session.createCriteria(ZPrincipal.class);
List<ZPrincipal> list = criteria.list();
Hibernate 运行以下查询:
select this_.username as username9_1_,
metadata2_.username as username9_3_,
metadata2_.meta_value as meta2_3_,
metadata2_.meta_key as meta3_3_
from users this_
left outer join user_metadata metadata2_ on this_.username=metadata2_.username
导致返回的行:
|username9_1_ |username9_3_ |meta2_3_ |meta3_3_ |
+--------------+--------------+----------+----------+
|admin |null |null |null |
|brett |brett |key1 |value1 |
|brett |brett |key2 |value2 |
+--------------+--------------+----------+----------+
这会产生一个包含 3 个实体(即“问题”)的用户列表,即“管理员”用户 对象和两个“brett”用户对象(相同)。两个“brett”实例确实包含一个正确填充的地图。对于那些想知道的人,ZPrincipal 类 确实 覆盖了 equals(),它提供了基于用户名(与主键相同)的比较,并且 覆盖 hashCode() 也对用户名进行哈希处理。
我们的商店采用“模式优先”设计,并且模式在数据库意义上似乎“正确”。可能这个问题可以通过干预映射表和在 user_metadata 表中生成的 id 来解决,但是从阅读可用的 JPA 和 Hibernate 文档 (http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection) 看来,应该只使用两个表来映射原始元素集合可能。
映射中缺少什么?或者它是Hibernate中的一个错误?如果是这样,任何人都可以想到一个映射解决方法吗?我已经把注释弄得乱七八糟了。
【问题讨论】:
-
貌似解决了。我会在这里为遇到此问题的其他人发布答案。当我将基于条件的查询替换为:
Query query = session.createQuery("FROM ZPrincipal");时,SQL 查询本身是相同的,但结果是正确唯一的 ZPrincipal 列表。恕我直言,这是一个 Hibernate 错误,因为“FROM ZPrincipal”在语义上应该等同于:Criteria criteria = session.createCriteria(ZPrincipal.class); List<ZPrincipal> list = criteria.list();