2017-05-30 81 views
0

嗨,我寫了下面的Criteria-API查詢,由於多選,創建一個損壞的sql-select語句。如果我取消註釋multiselect查詢按預期工作,但事情是我不想擁有所有數據。在我的門戶對象中有幾種關係,並且在我目前的情況下加載它們都是絕對沒有必要的。休眠打亂了我的查詢

的方法是這樣的:

@Override 
    public Optional<Portal> loadPortalData(long clientId) 
    { 
    log.trace("loading data for client with id '{}'", clientId); 
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 
    CriteriaQuery<Portal> criteriaQuery = criteriaBuilder.createQuery(Portal.class); 
    Root<Portal> root = criteriaQuery.from(Portal.class); 
    criteriaQuery.multiselect(root.get(Portal_.codes), 
           root.get(Portal_.certificate)) 
       .where(criteriaBuilder.equal(root.get(Portal_.id), clientId)); 
    try 
    { 
     return Optional.of(entityManager.createQuery(criteriaQuery).getSingleResult()); 
    } 
    catch (NoResultException noResult) 
    { 
     return Optional.empty(); 
    } 
    } 

和破碎的查詢看起來是這樣的:

30 Mai 2017 07:12:56,305 [main] TRACE mypackage.repository.PortalDaoImpl (PortalDaoImpl.java:39) - loading data for client with id '1' 
Hibernate: 
select 
    . as col_0_0_, 
    portal0_.certificate as col_1_0_ 
from 
    portal portal0_ 
inner join 
    Code authorisat1_ 
     on portal0_.id=authorisat1_.client_id 
inner join 
    certificate certificat2_ 
     on portal0_.certificate=certificat2_.id 
where 
    portal0_.id=1 

任何建議,爲什麼,如果我使用多選Hibernate是搞亂了我這樣的查詢?

編輯:

@Entity 
@Table(name = "portal") 
public class Portal 
{ 
    ... 
    @Valid 
    @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER, mappedBy = "client") 
    private Set<Code> codes = new HashSet<>(); 

    @Valid 
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    @JoinColumn(name = "certificate", referencedColumnName = "id") 
    private Certificate certificate; 
    ... 
} 

和代碼級

@Entity 
public class Code 
{ 

    @Id 
    @GeneratedValue 
    private long id; 

    @NotNull 
    @Column(nullable = false, unique = true) 
    private String code; 

    @NotNull 
    @ManyToOne(fetch = FetchType.EAGER, targetEntity = Portal.class) 
    @JoinColumn(name = "client_id", referencedColumnName = "id", nullable = false) 
    private Portal client; 

    @NotNull 
    @Temporal(TemporalType.TIMESTAMP) 
    @Column(nullable = false) 
    private Date creation_time; 

    @Column(nullable = false) 
    private int expires_in; 
    ... 
} 
+0

門戶實體的代碼是什麼?爲什麼不使用JPQL進行這樣的靜態查詢? –

+0

爲什麼門戶網站的代碼很重要? JPQL產生相同的錯誤 – Goldfish

+0

嘿,你是需要幫助的人。投票結束,因爲你不想提供所需的信息讓我幫你免費。 –

回答

1

你不能選擇整個集合(codes)。

假設你想要的結果的每一行組成的代碼證書的,在JPQL查詢應該是

select code, portal.certificate from Portal portal 
left join portal.codes as code 
where portal.id = :id 

因爲有代碼在給定的那當然會返回儘可能多的行門戶網站,而不只是一個。

避免加載門戶實體的其他列可能是不成熟的,不必要的優化。它應該是更容易只是做

em.find(Portal.class, id) 

,或者,如果要加載代碼和證書在同一查詢

select distinct portal from Portal portal 
left join fetch portal.certificate 
left join fetch portal.codes 
where portal.id = :id 

這將返回包含門戶網站的唯一行,與預取的一組代碼。

如果您確實希望自己的應用程序速度更快,您應該在默認情況下(尤其是許多關聯)使關聯更爲懶惰,並在需要時使用獲取聯接。