简体   繁体   中英

JPA Criteria API and Oracle JSON_TABLE function

I have a problem with writing criteria in java based on sql code, we must use JSON_TABLE function and search by parameters:

    select tab1.id
         from TABLE1 tab1
                  left join
              TABLE2 param_json on tab1.id = param_json.TABLE_1_ID,
              json_table(
                         param_json.PARAMS_JSON, '$[*]'
                         COLUMNS (
                             "paramCode" VARCHAR2(4000) PATH '$.paramCode',
                             "displayValue" VARCHAR2(4000) PATH '$.displayValue'
                             )
              ) jt
         where jt."paramCode" = 'param1' and lower(jt."displayValue") like '%value%');
    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
    CriteriaQuery<Long> query = builder.createQuery(Long.class);
    Root<Table1> table1Root = query.from(Table1.class);
    Join<Table1, Table2> jsonEJBJoin = table1Root.join(Table1_.table2Elements);
    
    //how add json_table function
    
    List<Predicate> whereConditions = new LinkedList<>();
    Predicate[] predicates = new Predicate[whereConditions.size()];
    
    //how add where conditions based on json_table function
    
     query.where(whereConditions.toArray(predicates));
     query.select(table1Root.get(Table1_.id));
    
      List<Long> resultList = getEntityManager().createQuery(query)
                    .setMaxResults(10)
                    .getResultList();

This is hard because you're using a screwdriver as a hammer. The whole point of the Criteria API is to have platform-independent code which doesn't depend on proprietary functions like json_table .

If you have database access, I think the cleanest way to resolve this is to create a view to hide all the Oracle-specific code from JPA, eg:

create or replace view VIEW1 (TABLE_1_ID, PARAMCODE, DISPLAYVALUE) as
    select param_json.TABLE_1_ID, jt.paramCode, jt.displayValue
    from TABLE2 param_json,
      json_table(
                 param_json.PARAMS_JSON, '$[*]'
                 COLUMNS (
                     paramCode VARCHAR2(4000) PATH '$.paramCode',
                     displayValue VARCHAR2(4000) PATH '$.displayValue'
                     )
      ) jt;

Then you replace Table2 in your JPA code with View1.

If you can't modify the database, I think you'll have to abandon the Criteria API and use a NativeQuery with bind variable parameters, something like:

List<Long> resultList = getEntityManager().createNativeQuery("select tab1.id
     from TABLE1 tab1
              left join
          TABLE2 param_json on tab1.id = param_json.TABLE_1_ID,
          json_table(
                     param_json.PARAMS_JSON, '$[*]'
                     COLUMNS (
                         paramCode VARCHAR2(4000) PATH '$.paramCode',
                         displayValue VARCHAR2(4000) PATH '$.displayValue'
                         )
          ) jt
        where jt.paramCode = :param1 and lower(jt.displayValue) like :param2))" )
    .setParameter("param1", param1)
    .setParameter("param2", "%" + value + "%" )
    .setMaxResults(10)
    .getResultList();

As a side note, I recommend never using the case-sensitive Oracle identifiers (with double quotes). Some Oracle tutorials use them, but they only make things more complicated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM