Using a sub-query inside a JPASQLQuery

566 views
Skip to first unread message

Harmen Weber

unread,
May 5, 2017, 11:22:22 AM5/5/17
to Querydsl
Hi,

in my project, I use Hibernate 5.1.0.Final as our JPA implementation and QueryDSL 4.0.9. Unfortunately, JPQL does not support all the features that native SQL supports. For example, JPQL does not support subqueries in the from clause. That's why thought I could solve this using a native query. So, I wrote a quick 'n' dirty test that tries to use a subquery in a JPASQLQuery (see code snippet below). Unfortunately, the test fails with the following error:

Caused by: org.h2.jdbc.JdbcSQLException: Function "DEVICE_LOCATION_LOG" not found; SQL statement:
select device.serialNumber, device.manufacturerDeviceId, cdl.locationReference.resourceBasePath, cdl.locationReference.tenant, cdl.locationReference.id
from device
left join device_location_log
(select locationLogEntry
from device_location_log locationLogEntry
where (locationLogEntry.begin is null or not locationLogEntry.begin > ?) and not (locationLogEntry.end is null or locationLogEntry.end < ?)) as cdl
on cdl
.device = device
where cdl.locationReference.resourceBasePath = ? and cdl.locationReference.tenant = ? and cdl.locationReference.id = ? [90022-191]


When I look at the query in the error above, I see that the left join looks indeed awkward: left join device_location_log (select ... .
It looks as if device_location_log is a function that is called.

Maybe I'm creating that subquery in a wrong way. Neither new JPASQLQuery(..) nor SQLExpressions.select(..) worked for me.

Any help from your side would be highly appreciated.

Best regards,
Harmen

@Test
   public void quickTest() {
       final H2Templates sqlTemplates = new H2Templates();

        // Define the sub query.
       final Instant currentTimestamp = now(getInstanceUTC()).toInstant();
       final JPASQLQuery<LocationLogEntry> currentDeviceLocationQuery = new JPASQLQuery<>(getEntityManager(), sqlTemplates)
                                                                                                       .select(locationLogEntry)
                                                                                                       .from(locationLogEntry)
                                                                                                       .where(locationLogEntry.begin.isNull()
                                                                                                                                    .or(locationLogEntry.begin.after(currentTimestamp)
                                                                                                                                                              .not()),
                                                                                                              locationLogEntry.end.isNull()
                                                                                                                                  .or(locationLogEntry.end.before(currentTimestamp))
                                                                                                                                  .not());

        // Execute the main query that uses the sub query.
       final QLocationLogEntry currentDeviceLocation = new QLocationLogEntry("cdl");
       final List<Tuple> results = new JPASQLQuery<>(getEntityManager(),
                                                     sqlTemplates).select(device.serialNumber,
                                                                          device.manufacturerDeviceId,
                                                                          currentDeviceLocation.locationReference.resourceBasePath,
                                                                          currentDeviceLocation.locationReference.tenant,
                                                                          currentDeviceLocation.locationReference.id)
                                                                  .from(device)
                                                                  .leftJoin(currentDeviceLocationQuery,
                                                                            currentDeviceLocation)
                                                                  .on(currentDeviceLocation.device.eq(device))
                                                                  .where(currentDeviceLocation.locationReference.resourceBasePath.eq(Location.RESOURCE_BASE_PATH),
                                                                         currentDeviceLocation.locationReference.tenant.eq("nestle.sa"),
                                                                         currentDeviceLocation.locationReference.id.eq(Long.valueOf(6)))
                                                                  .fetch();
       LOGGER.debug("Results: " + results);
   }


Reply all
Reply to author
Forward
Message has been deleted
0 new messages