渴望/延迟加载的成员总是为空,JPA 一对多关系
Posted
技术标签:
【中文标题】渴望/延迟加载的成员总是为空,JPA 一对多关系【英文标题】:Eager/Lazy loaded member always empty with JPA one-to-many relationship 【发布时间】:2010-04-09 19:01:24 【问题描述】:我有两个实体,用户和角色,用户与角色之间存在一对多关系。表格如下所示:
mysql> select * from User;
+----+-------+----------+
| id | name | password |
+----+-------+----------+
| 1 | admin | admin |
+----+-------+----------+
1 row in set (0.00 sec)
mysql> select * from Role;
+----+----------------------+---------------+----------------+
| id | description | name | summary |
+----+----------------------+---------------+----------------+
| 1 | administrator's role | administrator | Administration |
| 2 | editor's role | editor | Editing |
+----+----------------------+---------------+----------------+
2 rows in set (0.00 sec)
这是创建的连接表:
mysql> select * from User_Role;
+---------+----------+
| User_id | roles_id |
+---------+----------+
| 1 | 1 |
| 1 | 2 |
+---------+----------+
2 rows in set (0.00 sec)
这是定义表和关系的orm.xml
的子集:
<entity class="User" name="User">
<table name="User" />
<attributes>
<id name="id">
<generated-value strategy="AUTO" />
</id>
<basic name="name">
<column name="name" length="100" unique="true" nullable="false"/>
</basic>
<basic name="password">
<column length="255" nullable="false" />
</basic>
<one-to-many
name="roles"
fetch="EAGER"
target-entity="Role"
/>
</attributes>
</entity>
<entity class="Role" name="Role">
<table name="Role" />
<attributes>
<id name="id">
<generated-value strategy="AUTO"/>
</id>
<basic name="name">
<column name="name" length="40" unique="true" nullable="false"/>
</basic>
<basic name="summary">
<column name="summary" length="100" nullable="false"/>
</basic>
<basic name="description">
<column name="description" length="255"/>
</basic>
</attributes>
</entity>
然而,尽管如此,当我检索管理员用户时,我得到了一个空集合。我使用 Hibernate 作为我的 JPA 提供程序,它显示以下调试 SQL:
select
user0_.id as id8_,
user0_.name as name8_,
user0_.password as password8_
from
User user0_
where
user0_.name=? limit ?
当一对多映射被延迟加载时,这是唯一的查询。这会正确检索一个管理员用户。我将关系更改为使用急切加载,然后除了上述查询之外,还进行了以下查询:
select
roles0_.User_id as User1_1_,
roles0_.roles_id as roles2_1_,
role1_.id as id9_0_,
role1_.description as descript2_9_0_,
role1_.name as name9_0_,
role1_.summary as summary9_0_
from
User_Role roles0_
left outer join
Role role1_
on roles0_.roles_id=role1_.id
where
roles0_.User_id=?
结果如下:
+----------+-----------+--------+----------------------+---------------+----------------+
| User1_1_ | roles2_1_ | id9_0_ | descript2_9_0_ | name9_0_ | summary9_0_ |
+----------+-----------+--------+----------------------+---------------+----------------+
| 1 | 1 | 1 | administrator's role | administrator | Administration |
| 1 | 2 | 2 | editor's role | editor | Editing |
+----------+-----------+--------+----------------------+---------------+----------------+
2 rows in set (0.00 sec)
Hibernate 显然知道角色,但 getRoles()
仍然返回一个空集合。 Hibernate 也充分认识到这种关系,将数据放在首位。
什么问题会导致这些症状?
【问题讨论】:
【参考方案1】:在我看来,您的物理模型和实体映射之间存在某种不匹配:物理模型实现了多对多关系(使用连接表),而映射声明了一对多关系。 IMO,物理模型是“正确的”:一个用户可以有多个角色,一个角色可以关联到多个用户。换句话说,用户和角色之间的关系是多对多的。
【讨论】:
关于多对多关系的要点。因为我还不需要来自另一个方向的数据,所以我没有想到它,但这是真的。【参考方案2】:好的,我发现了导致问题的几个不同症状:
-
用户错误。在这种情况下,我错了,我上面的一切都正常工作。我犯了一个愚蠢的(好吧……真的很愚蠢)错误。
架构更改。在一对多和多对多关系之间切换时,架构已更新,但我的数据没有重新填充。由于未重新填充数据,连接表中的第三列为 NULL 且未使用,导致返回零记录。
多对多映射也有效。这是它最终的样子:
<entity class="User" name="User">
<table name="User" />
<attributes>
<id name="id">
<generated-value strategy="AUTO" />
</id>
<basic name="name">
<column name="name" length="100" unique="true" nullable="false"/>
</basic>
<basic name="password">
<column length="255" nullable="false" />
</basic>
<many-to-many
name="roles"
fetch="EAGER"
target-entity="Role"
/>
</attributes>
</entity>
<entity class="Role" name="Role">
<table name="Role" />
<attributes>
<id name="id">
<generated-value strategy="AUTO"/>
</id>
<basic name="name">
<column name="name" length="40" unique="true" nullable="false"/>
</basic>
<basic name="summary">
<column name="summary" length="100" nullable="false"/>
</basic>
<basic name="description">
<column name="description" length="255"/>
</basic>
<many-to-many
name="users"
mapped-by="roles"
/>
</attributes>
</entity>
事实证明,这两种解决方案都有效,但多对多解决方案假定我的角色对象中有一个字段,允许我查询(和/或设置)用户。这将使角色管理更容易。
【讨论】:
以上是关于渴望/延迟加载的成员总是为空,JPA 一对多关系的主要内容,如果未能解决你的问题,请参考以下文章
外键在一对多关系中始终为空 - Spring Boot Data with JPA