问题描述
我将 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;
}
现在我想找到所有按 Nation
和 ID
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);
但它不起作用;它按国家过滤,但不按国家过滤。
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) ...
尝试传递完整的实体以查看它是否有效.. . 如果失败,则回退以创建一个构造函数,该构造函数仅接收您的业务案例所需的属性。