2016-11-04 84 views
0

我們有2個Entites:一個員工講一組語言和一個員工進行的評論。將枚舉的ElementCollections與QueryDSL和Hibernate進行比較

@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只有在我們擁有一個Q語言並在e.languages上加入語言時纔有效。我們可以通過在語言中添加@Embeddable來生成這個,但是然後hibernate抱怨Language上缺少一個沒有參數的構造函數。

回答

0

到目前爲止,我們發現的唯一解決方法是剔除@ElementCollection,而不是引入EmployeeLanguage實體,該實體只持有對員工的引用和單個枚舉值。此代碼產生相同的DB模式作爲一個與差的問題,現在查詢語言是可能的:

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

}

@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; 
} 

現在這個查詢小改制後的作品