使用 QueryDsl 的多态 where 子句
Polymorphic where clause using QueryDsl
我正在尝试使用 QueryDsl 编写带有多态 where 子句的查询。
由于抽象地解释我想做什么有点困难,我 cloned the spring-boot-sample-data-jpa project 并对其进行了修改以显示我正在尝试做的事情的示例。
我有 these model classes,您会注意到 SpaHotel
和 SportHotel
扩展了 Hotel
实体。
我正在尝试编写一个查询,其中 return 包含 SpaHotel
或 SportHotel
的所有城市,其主要运动属于给定类型。
我写了一个JPQL version of that query,有点难看(我不喜欢sport is null
部分表示这是一家温泉酒店),但似乎return什么我要。
但是the QueryDsl version of that query好像不行:
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);
}
我的 test 失败了:
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)
我的查询似乎没有 return "Montreal",应该 returned,因为它包含 SpaHotel。
此外,我想知道 QueryDsl 将我的查询转换为交叉连接是否正常:
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=?)
我的问题:
- 为什么该查询不 returning "Montreal",其中包含
水疗酒店?
- 是否有更好的方式来编写该查询?
- 生成的SQL交叉连接正常吗?我们不能像我在 JPQL 中那样做左连接吗?
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)";
是
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);
在您的原始查询中,此 属性 用法
hotel.as(QSportHotel.class).mainSport
导致交叉连接并将查询限制为 SportHotels。
Querydsl 仅对仅在查询的 orderBy 部分使用的路径使用隐式左连接,一切都会导致隐式内部连接。
我正在尝试使用 QueryDsl 编写带有多态 where 子句的查询。
由于抽象地解释我想做什么有点困难,我 cloned the spring-boot-sample-data-jpa project 并对其进行了修改以显示我正在尝试做的事情的示例。
我有 these model classes,您会注意到 SpaHotel
和 SportHotel
扩展了 Hotel
实体。
我正在尝试编写一个查询,其中 return 包含 SpaHotel
或 SportHotel
的所有城市,其主要运动属于给定类型。
我写了一个JPQL version of that query,有点难看(我不喜欢sport is null
部分表示这是一家温泉酒店),但似乎return什么我要。
但是the QueryDsl version of that query好像不行:
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);
}
我的 test 失败了:
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)
我的查询似乎没有 return "Montreal",应该 returned,因为它包含 SpaHotel。
此外,我想知道 QueryDsl 将我的查询转换为交叉连接是否正常:
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=?)
我的问题:
- 为什么该查询不 returning "Montreal",其中包含 水疗酒店?
- 是否有更好的方式来编写该查询?
- 生成的SQL交叉连接正常吗?我们不能像我在 JPQL 中那样做左连接吗?
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)";
是
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);
在您的原始查询中,此 属性 用法
hotel.as(QSportHotel.class).mainSport
导致交叉连接并将查询限制为 SportHotels。
Querydsl 仅对仅在查询的 orderBy 部分使用的路径使用隐式左连接,一切都会导致隐式内部连接。