注意到:对不起。我不会说英语,所以我使用翻译器。
我使用 spring boot 和 spring data jpa 和 querydsl
我有 2 个实体和 2 个用于 api 服务的 dto
让我先向您展示实体和 dto
//package and imports...
@Entity
@Getter
@Setter(AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Event {
@Id
@GeneratedValue
private Long eventId;
private String requestBy;
private String content;
private String difficulty;
private String partyType;
private LocalDate eventDate;
private LocalTime eventTime;
private String comment;
@OneToMany(mappedBy = "event")
private List<Member> members = new ArrayList<>();
private Event(Event.Builder builder) {
this.requestBy = builder.requestBy;
this.content = builder.content;
this.difficulty = builder.difficulty;
this.partyType = builder.partyType;
this.eventDate = builder.eventDate;
this.eventTime = builder.eventTime;
this.comment = builder.comment;
}
public void addMember(Member member) {
this.members.add(member);
member.joinEvent(this);
}
public void addAllMember(Member... members) {
Arrays.stream(members).forEach(this::addMember);
}
@NoArgsConstructor
public static class Builder {
//... something builder codes
}
}
//package and imports...
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Member {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Event event;
private String name;
private String position;
public Member(String name, String position) {
this.name = name;
this.position = position;
}
void joinEvent(Event event) {
this.event = event;
}
}
//package and imports...
@Getter
@Setter
@NoArgsConstructor
public class EventDto {
private Long eventId;
private String requestBy;
private String content;
private String difficulty;
private String partyType;
private LocalDate eventDate;
private LocalTime eventTime;
private String comment;
private List<MemberDto> members = new ArrayList<>();
@QueryProjection
public EventDto(Long eventId, String requestBy, String content, String difficulty, String partyType, LocalDate eventDate, LocalTime eventTime, String comment, List<MemberDto> members) {
this.eventId = eventId;
this.requestBy = requestBy;
this.content = content;
this.difficulty = difficulty;
this.partyType = partyType;
this.eventDate = eventDate;
this.eventTime = eventTime;
this.comment = comment;
this.members = members;
}
public static EventDto convertEventToDto(Event event) {
EventDto dto = new EventDto();
dto.setEventId(event.getEventId());
dto.setRequestBy(event.getRequestBy());
dto.setContent(event.getContent());
dto.setDifficulty(event.getDifficulty());
dto.setPartyType(event.getPartyType());
dto.setEventDate(event.getEventDate());
dto.setEventTime(event.getEventTime());
dto.setComment(event.getComment());
event.getMembers().stream()
.map(member -> new MemberDto(member.getId(), member.getName(), member.getPosition()))
.forEach(memberDto -> dto.members.add(memberDto));
return dto;
}
}
//package and imports...
@Getter
@Setter
@NoArgsConstructor
public class MemberDto {
private Long memberId;
private String name;
private String position;
@QueryProjection
public MemberDto(Long memberId, String name, String position) {
this.memberId = memberId;
this.name = name;
this.position = position;
}
}
非常简单的实体和 DTO。 事件有成员/每个成员有一个事件。一对多/多对一 一般查询没有问题。
所以我尝试 querydsl 转换,但失败了
我想转换为 Map
public Map<LocalDate, List<EventDto>> findAllDtoByEventDateBetween(LocalDate start, LocalDate end) {
Map<LocalDate, List<EventDto>> transform = queryFactory
.from(event)
.join(event.members, member)
.where(event.eventDate.between(start, end))
.transform(
groupBy(event.eventDate).as(
list(new QEventDto(
event.eventId,
event.requestBy,
event.content,
event.difficulty,
event.partyType,
event.eventDate,
event.eventTime,
event.comment,
list(
new QMemberDto(
member.id.as("memberId"),
member.name.as("name"),
member.position.as("position")
)
)
))
)
);
return transform;
}
该代码抛出IllegalArgumentException:参数类型不匹配
所以我将其更改为使用投影
public Map<LocalDate, List<EventDto>> findAllDtoByEventDateBetween(LocalDate start, LocalDate end) {
Map<LocalDate, List<EventDto>> transform = queryFactory
.from(event)
.join(event.members, member)
.where(event.eventDate.between(start, end))
.transform(
groupBy(event.eventDate).as(
list(Projections.fields(
EventDto.class,
event.eventId,
event.requestBy,
event.content,
event.difficulty,
event.partyType,
event.eventDate,
event.eventTime,
event.comment,
list(
Projections.fields(
MemberDto.class,
member.id.as("memberId"),
member.name.as("name"),
member.position.as("position")
)
)
))
)
);
return transform;
}
它抛出org.springframework.dao.InvalidDataAccessApiUsageException:不支持的表达式new MemberDto(member1.id作为memberId,member1.name作为名称,member1.position作为位置);嵌套异常是 java.lang.IllegalArgumentException: 不支持的表达式 new MemberDto(member1.id as memberId, member1.name as name, member1.position asposition)
如果我使用 groupBy().list() 而不是 groupBy().as(list()) ,它可以完美地制作列表,但我想制作 Map 而无需在外部使用其他循环或流
我可以让 Map 仅使用 QueryDsl 吗?或者必须使用其他逻辑?
感谢阅读我的问题。再次抱歉,我的英语很糟糕。
最佳答案
Querdysl 工厂表达式(投影)不能与组表达式一起使用。对于使用 JPA 的高级 DTO 投影,请查看 Blaze-Persistence Entity Views(也有 Querydsl 集成)的示例。
关于spring-boot - 我在查询 dsl jpa 实体将 dto 转换为 map 时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74419837/