我们有2个参与者:一个说一组语言的员工和一个由员工进行的评论。
@Entity
public class Employee {
@ElementCollection
@CollectionTable(name = "employeeLanguage"
@Column(name = "language")
@Enumerated(EnumType.String)
private Set<Language> languages;
}
@Entity
public class Review {
@ManyToOne(fetch = FetchType.LAZY)
private Employee reviewer;
}
语言是一个简单的枚举:
public enum Language {
DE,
EN,
;
}
现在,如果已经完全覆盖了特定员工的语言,我们希望查询特定的评论子集。 (在SpecificReviewsSubset中所有Review.reviewer.languages的联合包含所有specificEmployee.languages)
我们正在使用以下查询尝试此操作:
private BooleanExpression hasAllEmployeeLanguagesCovered (List<Review> reviews, Employee employee) {
return new JPASubQuery().from(e)
.where(e.eq(employee))
.where(e.languages.any().in(
new JPASubQuery().from(r).join(r.reviewer, e)
.where(r.in(reviews)).distinct().list(e.languages.any()
)
.exists();
}
但是我们收到以下错误:
java.lang.IllegalArgumentException: Undeclared path 'e_languages_ed0e7'.
Add this path as a source to the query to be able to reference it.
我们如何在路径中添加e_languages? Afaik这只有在我们有QLanguage并加入e.languages语言时才有效。我们可以通过在语言中添加@Embeddable来生成这个,但是hibernate会抱怨语言中缺少no args构造函数。
答案 0 :(得分:0)
到目前为止,我们发现的唯一解决方法是抛弃@ElementCollection,而是引入一个EmployeeLanguage实体,它只包含对员工的引用和单个枚举值。此代码生成与问题中的模式相同的数据库模式,区别在于现在可以查询语言:
@Entity
public class Employee {
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL)
@Column(nullable = false)
@Getter @Setter
private Set<EmployeeLanguage> languages;
}
@Entity
public class EmployeeLanguage implements Serializable {
@Id
@ManyToOne(fetch = FetchType.LAZY)
@Getter @Setter
private Employee employee;
@Id
@Column(nullable=false)
@Enumerated(EnumType.STRING)
@Getter @Setter
private Language language;
}
现在这个查询在一次小型重组之后就可以了:
private BooleanExpression hasAllEmployeeLanguagesCovered (List<Review> reviews, Employee employee) {
return new JPASubQuery().from(el)
.where(el.employee.eq(employee))
.where(el.language.notIn(
new JPASubQuery().from(r).join(r.reviewer, e).join(e.languages, el)
.where(r.in(reviews)).list(el.language)
)
.notExists();
}