简体   繁体   English

渴望/延迟加载的成员总是空的,并且具有JPA一对多关系

[英]Eager/Lazy loaded member always empty with JPA one-to-many relationship

I have two entities, a User and Role with a one-to-many relationship from user to role. 我有两个实体,一个用户和一个角色,用户与角色之间存在一对多的关系。 Here's what the tables look like: 表格如下所示:

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)

And here's the join table that was created: 这是创建的联接表:

mysql> select * from User_Role;
+---------+----------+
| User_id | roles_id |
+---------+----------+
|       1 |        1 |
|       1 |        2 |
+---------+----------+
2 rows in set (0.00 sec)

And here's the subset of orm.xml that defines the tables and relationships: 这是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>

Yet, despite that, when I retrieve the admin user, I get back an empty collection. 但是,尽管如此,当我检索管理员用户时,我还是得到了一个空集合。 I'm using Hibernate as my JPA provider and it shows the following debug SQL: 我使用Hibernate作为我的JPA提供程序,它显示以下调试SQL:

select
    user0_.id as id8_,
    user0_.name as name8_,
    user0_.password as password8_ 
from
    User user0_ 
where
    user0_.name=? limit ?

When the one-to-many mapping is lazy loaded, that's the only query that's made. 延迟加载一对多映射时,这是唯一进行的查询。 This correctly retrieves the one admin user. 这将正确检索一个管理员用户。 I changed the relationship to use eager loading and then the following query is made in addition to the above: 我更改了关系以使用紧急加载,然后除了上述内容之外还进行了以下查询:

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

Which results in the following results: 结果如下:

+----------+-----------+--------+----------------------+---------------+----------------+
| 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 obviously knows about the roles, yet getRoles() still returns an empty collection. Hibernate显然知道角色,但是getRoles()仍然返回一个空集合。 Hibernate also recognized the relationship sufficiently to put the data in the first place. Hibernate还认识到这种关系足以将数据放在首位。

What problems can cause these symptoms? 什么问题会导致这些症状?

To me, there is some kind of mismatch between your physical model and the mapping of your entities: the physical model implements a many-to-many relation (with a join table) while the mapping declares a one-to-many relation. 对我而言,您的物理模型与实体的映射之间存在某种不匹配:物理模型实现了多对多关系(带有连接表),而映射则声明了一对多关系。 IMO, the physical model is "right": one User can have many Roles, one Role can be associated to many Users. IMO,物理模型是“正确的”:一个用户可以具有多个角色,一个角色可以与多个用户相关联。 In other words, the relation between User and Roles is a many-to-many. 换句话说,用户和角色之间的关系是多对多的。

Ok, I found a couple of different symptoms that cause the problem: 好的,我发现了导致问题的几种不同症状:

  1. User error . 用户错误 In this case, I was in error and everything I had above was working correctly. 在这种情况下,我出错了,上面的一切都正常运行。 I made a dumb, (ok... really dumb) mistake. 我犯了一个愚蠢的(好吧,真的很愚蠢)的错误。
  2. Schema changes . 模式更改 In switching between one-to-many and many-to-many relationships, the schema was updated but my data wasn't repopulated. 在一对多和多对多关系之间进行切换时,已更新了架构,但是没有重新填充我的数据。 Since the data wasn't repopulated, a third column in the join table was NULL and unused resulting in zero records returned. 由于未重新填充数据,因此联接表中的第三列为NULL,并且未使用,导致返回零记录。

The many-to-many mapping also works. 多对多映射也可以。 Here's what it ended up looking like: 最终结果如下所示:

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

It turns out that either solution works, but the many-to-many solution assumes that I have a field within my role object that allows me to query (and/or set) the users. 事实证明,这两种解决方案都可以,但是多对多解决方案假定我的角色对象中有一个字段,该字段允许我查询(和/或设置)用户。 This will make role management easier. 这将使角色管理更加容易。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM