我需要帮助在JPA中生成查询。我们说我有这些表
create table PERSON (
person_id number(3,0) not null primary key,
last_name varchar2(15) not null,
first_name varchar2(15) not null,
department varchar2(15) not null
);
create table PHONE (
phone_id number(3,0) not null primary key,
person_id number(3,0) not null,
phone_type varchar2(10) not null,
CONSTRAINT fk_person_id FOREIGN KEY (person_id)
REFERENCES person (person_id)
);
我想定义一个类似的查询:
select p1.person_id, p1.last_name, p1.first_name,
(select count(1) from phone p2
where p2.person_id = p1.person_id) as phone_count
from person p1;
我的JPA课程定义如下:
@Entity
@Table(name="PERSON")
@Transactional(readOnly=true)
public class Person {
@Id
@Column(name = "PERSON_ID")
private Integer personId;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "DEPARTMENT")
private String department;
@OneToMany
@LazyCollection(LazyCollectionOption.FALSE)
@Fetch(FetchMode.SELECT) // or @Fetch(FetchMode.JOIN)
@JoinColumn(name = "PERSON_ID", referencedColumnName="PERSON_ID")
private Set<Phone> phones;
.... getters and setters...
}
@Entity
@Table(name="PHONE")
@Transactional(readOnly=true)
public class Person {
@Id
@Column(name = "PHONE_ID")
private Integer phoneId;
@Column(name = "PERSON_ID")
private Integer personId;
@Column(name = "PHONE_TYPE")
private String phoneType;
.... getters and setters ...
}
由于我有动态where子句,即last_name,first_name,因此可以根据需要传入department组合。我有一个功能:
personRepository.findAll(spec, pageable);
帮助我解决动态where子句,然后通过getPhones.size()获取手机数量。它按预期工作。但是,它会产生N + 1问题。如果我有500多人,它会循环每个人的记录,并在电话桌上调用选择查询。我的问题是在这种情况下如何避免N + 1问题。
我正在考虑使用本机查询,而且我不知道如何使动态where子句工作(我的真实程序有超过15列要过滤)。感谢帮助。
答案 0 :(得分:0)
等效的JPA查询将是:
SELECT
p.personId, p.lastName, p.firstName,
(SELECT COUNT(ph) FROM p.phones ph)
WHERE ...
返回元组,即将其用作:
TypedQuery<Object[]> q = em.createQuery(_QUERY_FROM_ABOVE_, Object[].class);
List<Object[]> results = q.getResultList();
// results.get(0)[0] -> Integer personId
// results.get(0)[1] -> String lastName
// results.get(0)[2] -> String firstName
// results.get(0)[3] -> Long COUNT
您甚至可以询问整个Person
及其手机数量:
SELECT p, (SELECT COUNT(ph) FROM p.phones ph)
WHERE ...
使用与上述代码类似的代码,results.get(0)[0]
是整个Person
对象,results.get(0)[1]
的计数为Long
。