比较枚举的ElementCollections与QueryDSL和Hibernate

时间:2016-11-04 17:01:30

标签: java hibernate enums querydsl

我们有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构造函数。

1 个答案:

答案 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();

}