代码之家  ›  专栏  ›  技术社区  ›  Kaleb Pederson

热切/懒惰加载的成员总是空的,带有JPA一对多关系

  •  0
  • Kaleb Pederson  · 技术社区  · 16 年前

    我有两个实体,一个用户和一个角色,从用户到角色有一对多的关系。这是桌子的样子:

    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还充分认识到了将数据放在首位的关系。

    哪些问题会导致这些症状?

    2 回复  |  直到 16 年前
        1
  •  1
  •   Pascal Thivent    16 年前

    对我来说,物理模型和实体映射之间存在某种不匹配:物理模型实现多对多关系(使用联接表),而映射声明一对多关系。IMO,物理模型是“正确的”:一个用户可以有多个角色,一个角色可以关联到多个用户。换句话说,用户和角色之间的关系是多对多的。

        2
  •  0
  •   Kaleb Pederson    16 年前

    好吧,我发现了一些引起问题的不同症状:

    1. 用户错误 . 在这种情况下,我出错了,上面的所有东西都正常工作。我做了个哑巴,(好吧…真是愚蠢)错误。
    2. 模式变化 . 在一对多和多对多关系之间切换时,模式被更新,但我的数据没有被重新填充。由于没有重新填充数据,因此联接表中的第三列为空且未使用,因此返回了零条记录。

    多对多映射也可以工作。结果是这样的:

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

    结果表明,这两种解决方案都可以工作,但多对多解决方案假定我的角色对象中有一个字段,允许我查询(和/或设置)用户。这将使角色管理更容易。