Sto provando a utilizzare QueryDsl per scrivere una query con una clausola polimorfica.Polymorphic where clausola che utilizza QueryDsl
Dal momento che è un po 'difficile spiegare cosa voglio fare in astratto, sono cloned the spring-boot-sample-data-jpa project e lo ho modificato per mostrare un esempio di ciò che sto cercando di fare.
Ho these model classes, dove noterete che SpaHotel
e SportHotel
estendono l'entità Hotel
.
Sto tentando di scrivere una query che restituisce tutte le città che contengono uno SpaHotel
o uno SportHotel
il cui sport principale è del tipo specificato.
Ho scritto un JPQL version of that query, che è un po 'brutto (non mi piace la parte sport is null
per indicare che si tratta di un hotel Spa), ma sembra restituire quello che voglio.
Ma the QueryDsl version of that query non sembra funzionare:
public List<City> findAllCitiesWithSpaOrSportHotelQueryDsl(SportType sportType) {
QCity city = QCity.city;
QHotel hotel = QHotel.hotel;
return queryFactory.from(city)
.join(city.hotels, hotel)
.where(
hotel.instanceOf(SpaHotel.class).or(
hotel.as(QSportHotel.class).mainSport.type.eq(sportType)
)
).list(city);
}
mio test fallisce con:
test_findAllCitiesWithSpaOrSportHotelQueryDsl(sample.data.jpa.service.CityRepositoryIntegrationTests) Time elapsed: 0.082 sec <<< FAILURE!
java.lang.AssertionError:
Expected: iterable over [<Montreal,Canada>, <Aspen,United States>, <'Neuchatel','Switzerland'>] in any order
but: No item matches: <Montreal,Canada> in [<Aspen,United States>, <'Neuchatel','Switzerland'>]
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
at sample.data.jpa.service.CityRepositoryIntegrationTests.test_findAllCitiesWithSpaOrSportHotelQueryDsl(CityRepositoryIntegrationTests.java:95)
Sembra che la mia domanda non restituisce "Montreal", che dovrebbe essere restituita, poiché contiene un SpaHotel.
Inoltre, mi chiedo se è normale che QueryDsl si tradurrebbe mia domanda in un cross join:
select city0_.id as id1_0_, city0_.country as country2_0_, city0_.name as name3_0_
from city city0_
inner join hotel hotels1_
on city0_.id=hotels1_.city_id
cross join sport sport2_
where hotels1_.main_sport_id=sport2_.id and (hotels1_.type=? or sport2_.type=?)
Le mie domande:
- Perché è che query non ritorno "Montreal", che contiene a SpaHotel?
- C'è un modo migliore di scrivere quella query?
- È normale che l'SQL generato esegua un cross-join? Non possiamo fare un left-join come faccio in JPQL?
Molto interessante, non mi ero reso conto che si poteva usare 'as()' in un 'leftJoin()' per lanciare il percorso di un sottotipo. Risolve perfettamente il mio problema. Grazie mille per la risposta veloce e per lo sviluppo di QueryDsl. È meraviglioso. –