我们有三个类Case、Meeting和SpecialMeeting(下面的zie对象(。当我们以以下方式使用JPA标准Api时:
static Specification<Case> betweenEnddateSpecialMeeting(LocalDate start, LocalDate end) {
return (root, query, cb) -> {
if (start != null || end != null) {
Join<Case, SpecialMeeting> join = cb.treat(root.join(Case_.meetings), SpecialMeeting.class);
Path<LocalDate> pathEnddate = join.get(SpecialMeeting_.actuelEnddate);
return findByStartAndEndDate(start, end, cb, pathEnddate);
} else {
return null;
}
};
}
private static Predicate findByStartAndEndDate(LocalDate start, LocalDate end, CriteriaBuilder cb, Path<LocalDate> pathEnddate) {
if (start != null && end != null) {
return cb.and(cb.greaterThanOrEqualTo(pathEnddate, start),
cb.lessThanOrEqualTo(pathEnddate, end));
} else if (start != null) {
return cb.greaterThanOrEqualTo(pathEnddate, start);
} else {
return cb.lessThanOrEqualTo(pathEnddate, end);
}
}
Hibernate生成以下查询:
select
case0_.id as id1_73_,
case0_.identificationcode as identifi8_73_,
case0_.version as version15_73_
from
l_cases case0_
inner join
l_meetings meeting1_
on case0_.id=meeting1_.case_id
inner join
l_meetings meeting2_
on case0_.id=meeting2_.case_id
inner join
l_special_meetings meeting2_1_
on meeting2_.id=meeting2_1_.id
where
meeting2_1_.actuel_enddate<=?
我们用于子类型SpecialMeeting的cb.treat(root.join(Case_.meetings(,SpecialMeeting.class(,为l_meetings生成一个额外的内部联接。这会导致重复的记录。有人能帮我们在l_meetings上获得1个内部加入的正确查询吗?
我们使用以下版本:
hibernate 5.4.20-最终
春季启动:2.3.3.释放
此致,
Andre Torensma
上述示例中使用的实体。
@Slf4j
@Audited
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "L_CASES")
@SequenceGenerator(name = "LCN", sequenceName = "L_CASE_SEQ", allocationSize = 1)
public class Case implements IdentifiableEntity {
@Id
@Column(nullable = false, precision = 10)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "LCN")
private Long id;
@Version
private Long version;
@Column(precision = 50)
private String identificationcode;
@Valid
@OneToMany(mappedBy = "case", cascade = { CascadeType.ALL })
private List<Meeting> meetings = new ArrayList<>();
@Override
public String getidentificationCode() {
return identificationcode;
}
}
@Slf4j
@Audited
@Getter
@Setter
@Entity
@NoArgsConstructor
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE", length = 2, discriminatorType = DiscriminatorType.STRING)
@Table(name = "L_MEETINGS")
@SequenceGenerator(name = "LMS", sequenceName = "L_MEETINGS_SEQ", allocationSize = 1)
public class Meeting {
@Id
@Column(nullable = false, precision = 10)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "LMS")
private Long id;
@Version
private Long version;
@Column(length = 36)
private String identificationcode;
@Column(nullable = false)
private LocalDate ldate;
@Column(name = "DATETIME_REGISTRATION", nullable = false)
private LocalDateTime datetimeRegistration;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "MEETING_ID")
private Meeting relatedMeeting;
@ManyToOne
@JoinColumn(name = "CASE_ID", nullable = false)
private Case case;
public Optional<SpecialMeeting> getSpecialMeeting() {
if (this instanceof SpecialMeeting) {
return Optional.of((SpecialMeeting) this);
}
return Optional.empty();
}
}
@Audited
@Getter
@Setter
@Entity
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table(name = "L_SPECIAL_MEETINGS")
@DiscriminatorValue("BB")
public class SpecialMeeting extends Meeting {
@Column
private LocalDate startdate;
@Column
private LocalDate enddate;
@Column(name = "ACTUEL_ENDDATE")
private LocalDate actuelEnddate;
@Column
private String description;
}```
Hibernate的CriteriaBuilder.treat()
已损坏;参见例如HHH-16318。
一个简单的解决方法是将类似cb.treat(animal, Dog.class)
的表达式更改为((From<?, Dog>)(Object)animal)
。
这是有效的,因为没有";运行时类型检查";使用SQL时需要担心的问题。
当然,您需要添加@SuppressWarnings("unchecked")
。
众所周知,将treat()
与不同的继承策略结合使用相当麻烦。参见HHH-9594和相关问题,目前正在研究中
然而,我可以确认hibernate 6.1.3
工作得更好,但首选解决方案尚未构建
使用hibernate 6.1.3
和spring-boot 3.0.0-M4
生成查询
select
c1_0.id,
c1_0.identificationcode,
c1_0.version
from
l_cases c1_0
join
(l_meetings m1_0
join
l_special_meetings m1_1
on m1_0.id=m1_1.id)
on c1_0.id=m1_0.case_id
where
case
when case
when m1_1.id is not null then 1
when m1_0.id is not null then 0
end=1 then m1_1.actuel_enddate
else null
end>=?
由于您已经构建了一个适合您特定需求的解决方案,因此我不会详细介绍几种解决方案。已经有很多像这样的线索了。