2013-02-19 7 views
7

Próbuję zoptymalizować podstawowe zapytanie za pomocą JPQL w Spring Data, aby uniknąć wielu zapytań do bazy danych i pobrać wszystkie informacje w jednym zapytaniu za pomocą JOIN Fetch i I Otrzymuję ten wyjątek:JPQL Dołącz Fetch nie działa w stowarzyszeniu ManyToOne w Spring Data

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=Business.Countries,tableAlias=country1_,origin=BUSINESS.COAPPLICANTS coapplican0_,columns={coapplican0_.Country_Id ,className=com.medifast.entity.core.Country}}] [select count(ca) from com.medifast.entity.core.CoApplicant ca LEFT JOIN FETCH ca.country LEFT JOIN FETCH ca.state where ca.client.id = :clientId]; nested exception is java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=Business.Countries,tableAlias=country1_,origin=BUSINESS.COAPPLICANTS coapplican0_,columns={coapplican0_.Country_Id ,className=com.medifast.entity.core.Country}}] [select count(ca) from com.medifast.entity.core.CoApplicant ca LEFT JOIN FETCH ca.country LEFT JOIN FETCH ca.state where ca.client.id = :clientId] 
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:301) 

To jest mój Dao:

/** 
* Interface to handle persistence operations for CoApplicants. 
* 
*/ 
@Repository 
public interface ICoApplicantDao extends JpaRepository<CoApplicant, Long> 
{ 
    @Query("select ca from CoApplicant ca JOIN FETCH ca.country c where ca.client.id = :clientId") 
    Page<CoApplicant> findCoApplicantsByClient(@Param("clientId") Long clientId, Pageable pageable); 
} 

i to są moje podmioty:

@Entity 
@Table(name = "BUSINESS.COAPPLICANTS") 
@SQLDelete(sql = "UPDATE BUSINESS.COAPPLICANTS SET DELETED = 1 WHERE id = ?") 
@Where(clause = "DELETED <> 1") 
@Data 
@EqualsAndHashCode(callSuper = true) 
public class CoApplicant extends AbstractAuditableEntity 
{ 

    /** 
    * Serial. 
    */ 
    private static final long serialVersionUID = -297231024073091062L; 


    /** 
    * First name. 
    */ 
    @Column(name = "FirstName") 
    private String firstName; 

    /** 
    * Last name. 
    */ 
    @Column(name = "LastName") 
    private String lastName; 


    /** 
    * Recognition Name. 
    */ 
    private String recognitionName; 

    /** 
    * For the address line 1 field. 
    */ 
    private String addressLine1; 

    /** 
    * For the address line 2 field. 
    */ 
    private String addressLine2; 


    /** 
    * City. 
    */ 
    private String city; 

    /** 
    * State. 
    */ 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "State_Id") 
    private State state; 

    /** 
    * Zip Code. 
    */ 
    private String zipCode; 

    /** 
    * Country. 
    */ 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "Country_Id") 
    private Country country; 

    /** 
    * Email address. 
    */ 
    @Column(unique = true) 
    private String email; 

    /** 
    * Main Phone number. 
    */ 
    private String mainPhone; 

    /** 
    * Constructor. 
    */ 
    public CoApplicant() 
    { 
     super(); 
    } 
} 


/** 
* Country entity. 
*/ 
@Entity 
@Table(name = "Business.Countries") 
@SQLDelete(sql = "Update Business.Countries set deleted = 1 where id=?") 
@Where(clause = "deleted <> 1") 
@Data 
@EqualsAndHashCode(callSuper = true) 
public class Country extends AbstractAuditableEntity 
{ 

    /** 
    * Serial. 
    */ 
    private static final long serialVersionUID = -267110442898674427L; 

    /** 
    * Name of the country. 
    */ 
    private String name; 

    /** 
    * The orders for the client. 
    */ 
    @OneToMany(mappedBy = "country", cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
    private Collection<State> states; 

    /** 
    * Const. 
    */ 
    public Country() 
    { 
     super(); 
    }  

} 


    /** 
* State entity. 
*/ 
@Entity 
@Table(name = "Business.States") 
@SQLDelete(sql = "Update Business.States set deleted = 1 where id=?") 
@Where(clause = "deleted <> 1") 
@Data 
@EqualsAndHashCode(callSuper = true) 
public class State extends AbstractAuditableEntity 
{ 

    /** 
    * Serial. 
    */ 
    private static final long serialVersionUID = 8643487990581006632L; 

    /** 
    * Name of the state. 
    */ 
    private String name; 

    /** 
    * Code of the state. 
    */ 
    private String code; 

    /** 
    * Country to which this State belongs. 
    */ 
    @ManyToOne 
    @JoinColumn(name = "Country_Id") 
    private Country country; 


    /** 
    * Constr. 
    */ 
    public State() 
    { 
     super(); 
    } 
} 

Wszelkie spostrzeżenia, pomoc będą bardzo cenne.

Czysty SQL dla co chcę osiągnąć będzie wyglądać mniej więcej tak:

SELECT ca.Id 
     ,firstName 
     ,lastName 
     ,recognitionName 
     ,addressLine1 
     ,city 
     ,email 
     ,mainPhone 
     ,coun.name 
     ,sta.name 
    FROM coApplicants AS ca 
    LEFT JOIN countries AS coun 
    on ca.country_Id=coun.id 
    LEFT JOIN states AS sta 
    on ca.state_Id=sta.id 
+0

jak (i ​​dlaczego) można dołączyć przynieść torbę, podczas gdy po prostu powrocie licznik ()? –

+0

Hej guido, tylko zastanawiasz się, dlaczego tu jest, każdy CoApplicant powinien mieć tylko jedno państwo i tylko jedno państwo z nim powiązane. Następujące zapytanie SQL czysty dla co chcę osiągnąć prace perfekcyjnie: SELECT ca.Id , firstName , lastName , recognitionName , AddressLine1 , miasto , email , mainPhone , coun.name , sta.name OD coApplicants jako cA LEFT JOIN krajów jak otoczony zielenią \t na ca.country_Id = coun.id LEFT JOIN Zjednoczonych jako STA \t na ca.state_Id = sta.id – vanvasquez

+2

mam ten sam problem, problem jest z " Strona "i" FETCH ", jeśli zastąpisz ją Listą, będzie działać idealnie. znalazłeś rozwiązanie, jeśli tak, podziel się nim z nami :) –

Odpowiedz

10

Korzystanie z pagable kwerendy z JOIN FETCH jest to problem dla Hibernate.

Aby rozwiązać sytuację, należy umieścić countQuery - prawie taki sam jak oryginał, ale niepowiązane INNER JOIN (w końcu FETCHes) są usuwane.

Źródło rozwiązania można znaleźć tutaj: Spring-Data FETCH JOIN with Paging is not working

Więc rozwiązaniem dla Ciebie będzie:

@Query(
    value="select ca from CoApplicant ca JOIN FETCH ca.country c where ca.client.id = :clientId", 
    countQuery="select count(ca) from CoApplicant ca where ca.client.id = :clientId") 
Page<CoApplicant> findCoApplicantsByClient(@Param("clientId") Long clientId, Pageable pageable); 
+0

Wielkie dzięki, Joro, co zasugerowałeś, działa idealnie. – vanvasquez

+0

Wreszcie znalazłem to. Wielkie dzięki! –

+0

, ale powinniśmy dodać przecinek między dwoma parametrami @Query –

Powiązane problemy