Querydsl - 如何在 select 表达式中连接多个列的值?
Querydsl - How to join multiple column's value in select expression?
我将 Querydsl 与 spring 数据 jpa 一起使用。我已经实现了自定义存储库来查找人名。人员实体如下所示:
@Entity
@Table(name = "persons")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false, updatable = false)
private Long id;
@Column(name = "initial")
private String initial;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "archived")
private Boolean archived;
//Other columns here.. && Getter setter goes here
}
实现的自定义存储库:
@Repository
public class PersonRepositoryImpl extends QueryDslRepositorySupport
implements PersonRepositoryCustom {
public PersonRepositoryImpl() {
super(Person.class);
}
@Override
public List<String> getPersonNames() {
return getQuerydsl()
.createQuery()
.from(QPerson.person)
.where(QPerson.person.archived.eq(Boolean.FALSE))
.select(/*
want to select as a full name like
initial + firstName + lastName
*/)
.fetch();
}
}
在select表达式中,我想加入三列来构造全名。如果数据库有如下记录 -
id | initial | firstName | lastName | archived | ...
----------------------------------------------------
1 | "Mr" | "John" | "Snow" | 0 | ...
那我想select为"Mr John Snow"。 有什么办法吗?
我不想 select 整条记录来连接值,因为实体有其他列和很多关联,加载整条记录不好。
您可以 select 使用 Querydsl 文档中的 3.2.3. Constructor usage 仅需要 3 列。
通过这种方式,您将需要以编程方式加入它们,但您将 select 仅获得所需的 3 列。
创建一个只有您需要的字段的 class。
public class PersonDTO {
private String initial;
private String firstName;
private String lastName;
public PersonDTO(String initial, String firstName, String lastName) {
this.initial = initial;
this.firstName = firstName;
this.lastName = lastName;
}
}
然后您可以创建查询
query.from(QPerson.person)
.select(Projections.constructor(
PersonDTO.class,
QPerson.person.initial,
QPerson.person.firstName,
QPerson.person.lastName))
.fetch();
@chris-sekas 提供了一个很好的解决方案,但这是另一个似乎非常方便的解决方案。我使用 com.querydsl.core.Tuple
而不是创建新的 DTO。
QPerson person = QPerson.person;
List<Tuple> tuples = getQuerydsl()
.createQuery()
.from(person)
.where(person.archived.eq(Boolean.FALSE))
.select(person.initial,
person.firstName,
person.lastName)
.fetch();
List<String> names = tuples.stream()
.map(t ->
t.get(person.initial) +
" " +
t.get(person.firstName) +
" " +
t.get(person.lastName))
.distinct()
.collect(Collectors.toList());
当我们只需要很少的列的信息而不需要创建新的 DTO 时,它非常有用。
我将 Querydsl 与 spring 数据 jpa 一起使用。我已经实现了自定义存储库来查找人名。人员实体如下所示:
@Entity
@Table(name = "persons")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false, updatable = false)
private Long id;
@Column(name = "initial")
private String initial;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "archived")
private Boolean archived;
//Other columns here.. && Getter setter goes here
}
实现的自定义存储库:
@Repository
public class PersonRepositoryImpl extends QueryDslRepositorySupport
implements PersonRepositoryCustom {
public PersonRepositoryImpl() {
super(Person.class);
}
@Override
public List<String> getPersonNames() {
return getQuerydsl()
.createQuery()
.from(QPerson.person)
.where(QPerson.person.archived.eq(Boolean.FALSE))
.select(/*
want to select as a full name like
initial + firstName + lastName
*/)
.fetch();
}
}
在select表达式中,我想加入三列来构造全名。如果数据库有如下记录 -
id | initial | firstName | lastName | archived | ...
----------------------------------------------------
1 | "Mr" | "John" | "Snow" | 0 | ...
那我想select为"Mr John Snow"。 有什么办法吗?
我不想 select 整条记录来连接值,因为实体有其他列和很多关联,加载整条记录不好。
您可以 select 使用 Querydsl 文档中的 3.2.3. Constructor usage 仅需要 3 列。
通过这种方式,您将需要以编程方式加入它们,但您将 select 仅获得所需的 3 列。
创建一个只有您需要的字段的 class。
public class PersonDTO {
private String initial;
private String firstName;
private String lastName;
public PersonDTO(String initial, String firstName, String lastName) {
this.initial = initial;
this.firstName = firstName;
this.lastName = lastName;
}
}
然后您可以创建查询
query.from(QPerson.person)
.select(Projections.constructor(
PersonDTO.class,
QPerson.person.initial,
QPerson.person.firstName,
QPerson.person.lastName))
.fetch();
@chris-sekas 提供了一个很好的解决方案,但这是另一个似乎非常方便的解决方案。我使用 com.querydsl.core.Tuple
而不是创建新的 DTO。
QPerson person = QPerson.person;
List<Tuple> tuples = getQuerydsl()
.createQuery()
.from(person)
.where(person.archived.eq(Boolean.FALSE))
.select(person.initial,
person.firstName,
person.lastName)
.fetch();
List<String> names = tuples.stream()
.map(t ->
t.get(person.initial) +
" " +
t.get(person.firstName) +
" " +
t.get(person.lastName))
.distinct()
.collect(Collectors.toList());
当我们只需要很少的列的信息而不需要创建新的 DTO 时,它非常有用。