JPA 2 关系 JOIN 命名查询

问题描述

我将 SpringBoot 2.4 与 JPA 2.0 一起使用,我有一个如下所示的模型:

@Entity
@Data
public class Nation {
   @Id 
   @GeneratedValue (strategy = GenerationType.IDENTITY)
   private Integer id;

   @OnetoMany(mappedBy = "nation")
   private List<Country> country;
}

还有:

@Entity
@Data
public class Country {
   @Id 
   @GeneratedValue (strategy = GenerationType.IDENTITY)
   private Integer id;

   @ManyToOne
   private Nation nation;
}

现在我想找到所有按 NationID country 过滤的 ID。在纯 sql 中只是类似于:

select * from nation n,country c where n.id = [nation_id] AND c.id = [country_id];

因此我想用 JPA 这样做:

@Query("select n from Nation n JOIN n.country c where n.id = ?1 AND c.id = ?2)
public List<Nation> find(Integer nationID,Integer countryID);

但它不起作用;它按国家过滤,但不按国家过滤。

如果我通过添加打印 Hibernate 生成 sql

spring.jpa.show.sql=true

我可以看到查询与我上面在纯 sql 中发布的完全相同。当我调用 nation.getCountry() 时出现问题,它会生成一个查询,加载所有连接到给定国家 ID 的国家。

有没有办法解决这个问题?

解决方法

我相信您可以在这种情况下使用 JPA DTO projections ...

所以,在你的 Nation 类中创建一个像这样的构造函数:

 /**
  * Copy Constructor. It creates a "detached" copy of the
  * given nation with only a copy of the provided country.
  */
 public Nation(Nation n,Country c) {
     super();
     this.id = n.id;
     // copy other nation values ...

     this.country.add( new Country(c) );
 }

修改你的查询以调用这样的构造函数......像这样(假设在java包Nation中声明了my.domain):

@Query("select new my.domain.Nation(n,c) from Nation n JOIN n.country c where n.id = ?1 AND c.id = ?2)

免责声明:

  • 我已经使用 JPA 和休眠完成了这项工作。到目前为止,我还没有使用 spring 进行测试,但我想这并不重要,因为您的 JPA 提供程序可能也处于休眠状态。
  • 我仅使用目标实体的部分(或属性)完成此操作(如提供的链接中所述)......我从未传递完整实体(正如我在查询中建议的那样)。让我解释一下,在我应用它的情况下,我有一个像 Nation(String name,int population) 这样的构造函数,并且在查询中我做了类似的事情:SELECT new my.domain.Nation(n.name,c.population) ... 尝试传递完整的实体以查看它是否有效.. . 如果失败,则回退以创建一个构造函数,该构造函数仅接收您的业务案例所需的属性。