@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "simple_entity")
public class SimpleEntity {
@Id
private Long id;
@Column(name = "text")
private String text;
}
我想从数据库中获取一些带有附加列的实体。为此,我创建了一个简单的Pair类。
@Getter @Setter @AllArgsConstructor public class Pair<First, Second> { private First first; private Second second; }
然后我在JPQL中准备了一个查询,该查询创建了预期的结果。
@Repository public interface SimpleEntityRepository extends JpaRepository<SimpleEntity, Long> { @Query("SELECT new com.example.demo.Pair(m, false) FROM SimpleEntity m") List<Pair<SimpleEntity, Boolean>> getRecords(); }
查询返回正确的结果,但是其他查询存在问题。因此,我有一些问题:
为什么JPA这样工作?
- 有没有办法在JPQL的一个查询中获取此数据?
- 我应该如何获得实体以及一些其他数据(我已经看到了返回Object []的解决方案,但是看起来不太好)?
结果转换器
当您将问题标记为休眠时,可以使用休眠结果转换器(在5.2中已弃用,但Alpha中仍为6.0:]List<Pair<SimpleEntity, Boolean>> resultList = entityManager.createQuery(
"select m as first, false as second from SimpleEntity m")
.unwrap(org.hibernate.query.Query.class)
.setResultTransformer(Transformers.aliasToBean(Pair.class))
.getResultList();
这假设Pair
具有无参数构造函数并产生:
select simpleenti0_.id as col_0_0_, 0 as col_1_0_, simpleenti0_.id as id1_18_, simpleenti0_.text as text2_18_ from simple_entity simpleenti0_
使用可以通过字段列表而非整个实体构造的类。当您指定选定字段的列表而不是整个实体时,查询将表现良好。正确的DTO
public class SimpleEntityDTO {
private Long id;
private String text;
private Boolean second;
public SimpleEntityDTO() {
}
public SimpleEntityDTO(Long id, String text, Boolean second) {
this.id = id;
this.text = text;
this.second = second;
}
// getters and setters
}
并修改您的查询:
@Query("SELECT new com.example.demo.SimpleEntityDTO(m.id, m.text, false) FROM SimpleEntity m")
List<SimpleEntityDTO> getRecordsExtended();
这产生了:
select
simpleenti0_.id as col_0_0_,
simpleenti0_.text as col_1_0_,
0 as col_2_0_
from
simple_entity simpleenti0_
我相信,对投影中的实体使用DTO的原因之一是,它们不受管理。在您的情况下,如果实体是DTO的一部分,则对实体进行管理:一般性备注
@Transactional
public void changeValueInFirstRecord() {
List<Pair<SimpleEntity, Boolean>> all = simpleEntityRepository.getRecords();
SimpleEntity firstEntity = all.get(0).getFirst();
boolean managed = entityManager.contains(firstEntity);
System.out.println("managed: " + managed); // true
firstEntity.setText("new value"); // firstEntity is updated
}
对于结果转换器也是如此:
@Transactional
public void changeValueInFirstEntityViaTransformer() {
List<Pair<SimpleEntity, Boolean>> all = entityManager.createQuery(
"select m as first, false as second from SimpleEntity m")
.unwrap(org.hibernate.query.Query.class)
.setResultTransformer(Transformers.aliasToBean(Pair.class))
.getResultList();
SimpleEntity firstEntity = all.get(0).getFirst();
boolean managed = entityManager.contains(firstEntity);
System.out.println("managed: " + managed); // true
firstEntity.setText("new_value"); // firstEntity is updated
}