Ich versuche QueryDsl zu verwenden, um eine Abfrage mit einem polymorphen where-Klausel zu schreiben.Polymorphe wo Klausel QueryDsl
Da es ein wenig schwierig ist zu erklären, was ich in der Zusammenfassung tun möchte, habe ich cloned the spring-boot-sample-data-jpa project geändert und es um ein Beispiel zu zeigen, was ich versuche zu tun.
Ich habe these model classes, wo Sie beachten Sie werden feststellen, dass SpaHotel
und SportHotel
die Hotel
Einheit erstrecken.
Ich versuche, eine Abfrage zu schreiben, die alle Städte zurückgibt, die entweder SpaHotel
oder SportHotel
enthalten, deren Hauptsport vom gegebenen Typ ist.
Ich schrieb eine JPQL version of that query, die ein wenig hässlich ist (ich mag nicht die sport is null
Teil, um anzuzeigen, dass es ein Spa-Hotel ist), aber scheint zurück, was ich will.
Aber the QueryDsl version of that query nicht zu funktionieren scheint:
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);
}
Mein test schlägt mit:
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)
Es ist wie meine Frage scheint nicht zurück "Montreal", die zurückgegeben werden sollen, da es ein SpaHotel enthält.
Auch frage ich mich, ob es normal ist, dass QueryDsl würde meine Abfrage in eine Cross-Join übersetzen:
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=?)
Meine Fragen:
- Warum ist diese Abfrage nicht "Montreal" Rückkehr, die enthält ein Spahotel?
- Gibt es eine bessere Art und Weise, dass die Abfrage des Schreibens?
- Ist es normal, dass die erzeugte SQL tut eine Quer beitreten? Können wir nicht einen Links-Join erstellen, wie ich es in JPQL mache?
Sehr interessant, ich wusste nicht, dass Sie 'wie()' in a 'leftJoin()' werfen den Pfad zu einem Subtyp nutzen könnten. Es löst mein Problem perfekt. Vielen Dank für die schnelle Antwort und für die Entwicklung von QueryDsl. Es ist toll. –