2015-03-26 22 views
9

Próbuję użyć QueryDsl, aby napisać zapytanie z klauzulą ​​polimorficzną gdzie.Polimorficzne klauzula where przy użyciu QueryDsl

Ponieważ trochę trudno wyjaśnić, co chcę zrobić w streszczeniu, I cloned the spring-boot-sample-data-jpa project i zmodyfikowałem, aby pokazać przykład tego, co próbuję zrobić.

mam these model classes, na której znajdą Państwo uwagę, że SpaHotel i SportHotel przedłużyć podmiot Hotel.

Próbuję napisać zapytanie, które zwraca wszystkie miasta zawierające albo SpaHotel, albo SportHotel, którego głównym sportem jest dany typ.

Napisałem JPQL version of that query, który jest trochę brzydka (ja nie lubię sport is null część oznaczać, że jest to Spa), ale wydaje się, aby powrócić czego chcę.

Ale the QueryDsl version of that query nie wydają się działać:

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

My test nie powiedzie się z:

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) 

Wydaje się, że moje zapytanie nie zwraca "Montreal", która powinna zostać zwrócona, ponieważ zawiera SpaHotel.

Również zastanawiam się, czy to normalne, że QueryDsl by tłumaczyć moje zapytanie do krzyża dołączyć:

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=?) 

Moje pytania:

  1. Dlaczego to zapytanie nie wracać „Montreal”, który zawiera a Spa2? ?
  2. Czy istnieje lepszy sposób napisania tego zapytania?
  3. Czy to normalne, że wygenerowany kod SQL łączy się krzyżowo? Czy nie możemy zrobić lewostronnego połączenia, tak jak robię to w JPQL?

Odpowiedz

3

Prawidłowa przemiana zapytaniu JPQL

String jpql = "select c from City c" 
    + " join c.hotels hotel" 
    + " left join hotel.mainSport sport" 
    + " where (sport is null or sport.type = :sportType)"; 

jest

return queryFactory.from(city) 
    .join(city.hotels, hotel) 
    .leftJoin(hotel.as(QSportHotel.class).mainSport, sport) 
    .where(sport.isNull().or(sport.type.eq(sportType))) 
    .list(city); 

W pierwotnym zapytaniu to wykorzystanie nieruchomość

hotel.as(QSportHotel.class).mainSport 

powoduje krzyż dołączyć i ograniczenia zapytanie do SportHotels.

Querydsl używa niejawnych lewych połączeń tylko dla ścieżek, które są używane tylko w części Zapytanie, wszystko spowoduje niejawne wewnętrzne sprzężenia.

+0

Bardzo interesujące, nie zdawałem sobie sprawy, że można użyć 'as()' w 'leftJoin()', aby rzucić ścieżkę do podtypu. Idealnie rozwiązuje mój problem. Wielkie dzięki za szybką odpowiedź i za opracowanie QueryDsl. To jest zajebiste. –

Powiązane problemy