【问题标题】:JPA native query with annotation executes different query带有注释的 JPA 本机查询执行不同的查询
【发布时间】:2018-08-03 10:53:54
【问题描述】:

我正在尝试实现这样的示例:Person 类有一个它喜欢的地方的列表。但是当我想查询它时,我希望结果是每个人只有最喜欢的地方(只是第一个而不是全部)。所以我这样做了:

@Entity
class Person{

    ...

    @ManyToMany(cascade = {CascadeType.REFRESH,CascadeType.PERSIST}, fetch = FetchType.EAGER)
    @JoinTable(name = "person_favorite_place",
            joinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "place_id", referencedColumnName = "id")
    )
    @OrderColumn(name="favorite_place_order")
    List<Place> favoritePlaces;
}

在存储库中,我做到了:

public interface PersonRepository extends JpaRepository<Person, Long> {

    @Query(value = "select person0_.id as id1_0_0_, person0_.age as age2_0_0_, person0_.name as name3_0_0_, favoriteme1_.person_id as person_id1_1_1_, place2_.id as place_id2_1_1_, favoriteme1_.favorite_place_order as favorite3_1_, place2_.id as id1_3_2_, place2_.invented as invented2_3_2_, place2_.name as name3_3_2_ from person person0_ left outer join person_favorite_place favoriteme1_ on person0_.id=favoriteme1_.person_id left outer join place place2_ on favoriteme1_.place_id=place2_.id where person0_.id=:personId  and favoriteme1_.favorite_place_order = 0", nativeQuery = true)
    Person getPersonWithFavoritePlace(@Param("personId") Long personId);

}

但似乎有 2 个 sql 查询正在运行。第一个是:

select person0_.id as id1_0_0_, person0_.age as age2_0_0_, person0_.name as name3_0_0_, favoriteme1_.person_id as person_id1_1_1_, place2_.id as place_id2_1_1_, favoriteme1_.favorite_place_order as favorite3_1_, place2_.id as id1_3_2_, place2_.invented as invented2_3_2_, place2_.name as name3_3_2_ from person person0_ left outer join person_favorite_place favoriteme1_ on person0_.id=favoriteme1_.person_id left outer join place place2_ on favoriteme1_.place_id=place2_.id where person0_.id=:personId  and favoriteme1_.favorite_place_order = 0

第二个:

select favoriteme0_.person_id as person_id1_1_0_, favoriteme0_.place_id as place_id2_1_0_, favoriteme0_.favorite_place_order as favorite3_0_, place1_.id as id1_3_1_, place1_.invented as invented2_3_1_, place1_.name as name3_3_1_ from person_favorite_place favoriteme0_ inner join place place1_ on favoriteme0_.place_id=place1_.id where favoriteme0_.person_id=?

我可以理解第一个,这完全是我要执行的查询,但第二个,我不知道它来自哪里。所以我认为,正因为如此,我拥有一个人所有最喜欢的地方,但不是最想要的。

有什么想法吗?

BR

PS:我已经在“findOne”方法的本机输出上编写了查询。最后添加了“and favoriteme1_.favorite_place_order = 0”。我也尝试过不加修改地使用确切的查询,它就像一个魅力!!

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    第二个查询用于加载您使用 FetchType.EAGER 定义的 favoritePlaces

    【讨论】:

    • 我现在,但重点是:当我用 findOne(id) 替换我的自定义方法时,它只运行一个 sql 查询。此外,我自己的查询中已经包含了 favoritePlaces。那么为什么它会执行另一个呢?
    • 如果你执行 findOne 它将执行这两个表的 JOIN。但是当您创建自己的 SQL 时,它认为没有足够的数据来构建 favoritePlaces。你的 SQL 和 findOne 的一样吗?
    • in findOne(id) hibernate 可以用 JOIN 构造一个查询,并且可以确定这个查询是正确的,并且可以将结果映射到您的集合中。使用您的查询购买它不能确定是否加载了所有必要的列。加载不完整的集合也是一种危险的方式,如果在任何地方,您将在 Person 实体上调用 save() 所有其他都可以删除。
    • 是的,我实际上已经用它构建了我的 sql。最后只加了“and favoriteme1_.favorite_place_order = 0”
    【解决方案2】:

    您的存储库正在查询人员而不是地点,并且由于 FetchType.EAGER 还使用第二个查询加载了所有地点;要查询 Places,请使用 PlacesRepository。

    【讨论】:

    • 是的,但我的查询也获取了它需要的所有内容。为什么 JPA 会再次尝试获取?也请检查我写西蒙的评论
    • Hibernate 不会分析您的原生查询,它只是了解结果应该是 Person 并将必要的字段映射到 person。任何其他列都将被忽略。
    • 我调用findOne(id)方法时怎么不执行secondary?
    • 我相信它使用连接而不是单独的查询。它不能依赖于您的本机查询连接。
    猜你喜欢
    • 2019-04-15
    • 2021-11-19
    • 2020-02-19
    • 2020-09-05
    • 2018-05-27
    • 2017-04-21
    • 2020-05-14
    • 1970-01-01
    • 2018-09-05
    相关资源
    最近更新 更多