2

この SQL クエリは、実行時に必要なことを正確に行います。JPA基準に相当するものを探していますか? 基本的に、1 対多の関係からデバイス エンティティと最新 (最大) の GPS 座標を取得します。

SELECT DISTINCT t0.DEVICE_I, t0.ACTIVE_S, t0.APP_CONFIG_I, t0.PREV_APP_CONFIG_I, 
t0.APP_CONFIG_CONFIRMED_S, t0.APP_CONFIG_RECEIPT_D, t0.APP_CONFIG_SENT_S, t0.CHANNEL_X, 
t0.CREATION_TS, t0.CREATION_USER_I, t0.DEST_QUEUE_C, t0.DIVISION_C, t0.LAN_IP_X, 
t0.LAST_UPDATE_TS, t0.LAST_UPDATE_USER_I, t0.MOBILE_IP_X, t0.ORIGIN_MP_I, 
t0.PREV_CHANNEL_X, t0.TELEPHONE_NUMBER_X, t0.VERSION_X, t1.DEVICE_I, t1.COORDINATE_I, 
t1.CREATION_TS, t1.CREATION_USER_I, t1.GENERATED_TS, t1.GPGGA_X, t1.GPGSA_X, 
t1.GPGSV_X, t1.GPRMC_X, t1.GPVTG_X, t1.LAST_UPDATE_TS, t1.LAST_UPDATE_USER_I, 
t1.WORK_ORDER_NUMBER_I 

FROM DEVICE t0, GPS_COORD t1 

WHERE  t0.DEVICE_I = t1.DEVICE_I AND  
t1.GENERATED_TS IN ( select max(GENERATED_TS)
       from GPS_COORD
      group by DEVICE_I )
ORDER BY t1.DEVICE_I ASC, t1.GENERATED_TS DESC

以下の Java コードはほぼ完成しており、GpsCoord から必要な結合フィールドが欠落している次のクエリを生成します。これらのフィールドは、フェッチが行われた場合に含まれますが、後でサブクエリの where 句で Join が必要になります。

    CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

    CriteriaQuery<Device> cq = criteriaBuilder.createQuery(Device.class);

    Root<Device> device = cq.from(Device.class);
    cq.distinct(true);

    Join<Device, GpsCoord> j = device.join(Device_.gpsCoords, JoinType.LEFT);
    //Fetch<Device,GpsCoord> f = device.fetch(Device_.gpsCoords);
    
    CriteriaQuery<Device> select = cq.select(device);


    Subquery<Timestamp> sq = cq.subquery(Timestamp.class);
    Root<GpsCoord> gpsCoord = sq.from(GpsCoord.class);

    sq.select(criteriaBuilder.greatest(gpsCoord.get(GpsCoord_.generatedTs)));
    sq.groupBy(gpsCoord.get(GpsCoord_.device).get(Device_.deviceI));
    select.where(j.get(GpsCoord_.generatedTs).in(sq));
    
    
    TypedQuery<Device> query = this.getEntityManager().createQuery(cq);

生成されたクエリには、結合操作からの GpsCoord フィールドがありません

SELECT DISTINCT t0.DEVICE_I, t0.ACTIVE_S, t0.APP_CONFIG_I, t0.PREV_APP_CONFIG_I,     
t0.APP_CONFIG_CONFIRMED_S, t0.APP_CONFIG_RECEIPT_D, t0.APP_CONFIG_SENT_S, 
t0.CHANNEL_X,     t0.CREATION_TS, t0.CREATION_USER_I, t0.DEST_QUEUE_C, t0.DIVISION_C, 
t0.LAN_IP_X, t0.LAST_UPDATE_TS, t0.LAST_UPDATE_USER_I, t0.MOBILE_IP_X, t0.ORIGIN_MP_I, 
t0.PREV_CHANNEL_X, t0.TELEPHONE_NUMBER_X, t0.VERSION_X 

FROM SPW_OWN.DEVICE t0, SPW_OWN.GPS_COORD t1 

WHERE (t1.GENERATED_TS IN (SELECT MAX(t2.GENERATED_TS) FROM SPW_OWN.GPS_COORD t2, 
SPW_OWN.DEVICE t3 WHERE t2.DEVICE_I = t3.DEVICE_I GROUP BY t3.DEVICE_I)) 

AND t0.DEVICE_I = t1.DEVICE_I(+)

このように CriteriaQuery から複数選択を使用すると、実行時に適切な SQL が生成されますが、次の例外が発生します。

Caused by: java.lang.Exception: java.lang.RuntimeException: Can not find constructor for "class Device" with argument types "[class java.lang.String ... java.sql.Timestamp]" to fill data.   

呼び出し後にスローされます:

CriteriaQuery<Device> select = cq.multiselect(
                    //"deviceI",
                    device.get(Device_.deviceI),
                    //"activeS",
                    device.get(Device_.activeS),
                    //"appConfigConfirmedS",
                    device.get(Device_.appConfigConfirmedS),
                    //"appConfigReceiptD",
                    device.get(Device_.appConfigReceiptD),
                    //"appConfigSentS",
                    device.get(Device_.appConfigSentS),
                    //"channelX",
                    device.get(Device_.channelX),
                    //"destQueueC",
                    device.get(Device_.destQueueC),
                    //"lanIpX",
                    device.get(Device_.lanIpX),
                    //"mobileIpX",
                    device.get(Device_.mobileIpX),
                    //"prevChannelX",
                    device.get(Device_.prevChannelX),
                    //"telephoneNumberX",
                    device.get(Device_.telephoneNumberX),
                    //"versionX"
                    device.get(Device_.versionX),
                    //"device",
                    j.get(GpsCoord_.device),
                    //"gpggaX",
                    j.get(GpsCoord_.gpggaX),
                    //"gprmcX",
                    j.get(GpsCoord_.gprmcX),
                    //"gpgsaX",
                    j.get(GpsCoord_.gpgsaX),
                    //"gpgsvX",
                    j.get(GpsCoord_.gpgsvX),
                    //"gpvtgX"
                    j.get(GpsCoord_.gpvtgX),
                    j.get(GpsCoord_.generatedTs)
                    );
4

1 に答える 1

1

いくつかの問題、

  • あなたが呼び出す、sq.from(GpsCoord.class); 二回
  • device.fetch(Device_.gpsCoords) の使用; オブジェクトも取得し、2 回結合します
  • あなたのINは間違っています。

select.where(criteriaBuilder.get(path).in(sq));

于 2013-02-05T15:23:20.190 に答える