JPA准则API使用子类型类生成额外的内部联接



我们有三个类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.3spring-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>=?

由于您已经构建了一个适合您特定需求的解决方案,因此我不会详细介绍几种解决方案。已经有很多像这样的线索了。

相关内容

  • 没有找到相关文章

最新更新