Search code examples
javaeclipselinkjpa-2.0

eclipselink jpa criteria reference unmapped column


when writing jpql queries I can reference not mapped columns with COLUMN() (I know it is eclipselink specific). Is there any way I can reference unmapped column when building criteria using javax.persistence.criteria.CriteriaBuilder, javax.persistence.criteria.Predicate, etc?

The problem I am facing: I have postgresql table with full text search column. I do not want it to be mapped to entity objects but I qould like to use is in queries (and I need also queries using CriteriaBuilder).


Edit: code example

I have a table: X (id integer, name varchar, fts tsvector)

"fts" column is full text search index data. I need entity class without "fts" attribute, like:

@Entity class X {
    @Id Integer id;
    @Column String name;
}

so that fts data is never fetched (for performance), but I need to be able to query that column. I can do this with jpql: SELECT t FROM X t WHERE COLUMN('fts', t) IS NOT NULL;

but how can I reference such column when building criteria like:

Specification<Fts> spec = new Specification<Fts>() {
        @Override
        public Predicate toPredicate(Root<Fts> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
            return builder.notNull(root.<String>get("fts"));
        }
    };

other choice: How to add attribute in entity class that reference table column but is never fetched? I tried adding @Basic(fetchType = FetchType.LAZY) but it does not work and value is fetched upon query...


Solution

  • Ok. I managed to solve it this way:

    Specification<Fts> spec = new Specification<Fts>() {
            @Override
            public Predicate toPredicate(Root<Fts> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                JpaCriteriaBuilder cb = (JpaCriteriaBuilder) builder;
                List<String> args = new ArrayList();
                args.add("FTS query");
    
                javax.persistence.criteria.Expression<Boolean> expr = cb.fromExpression(
                  cb.toExpression(
                    cb.function("", Boolean.class, cb.fromExpression(((RootImpl) root).getCurrentNode().getField("fts")))
                  )
                  .sql("? @@ to_tsquery(?)", args)
                );
                // getField() allows to reference column not mapped to Entity
    
                query.where(expr);
    
                return null; // or return cb.isTrue(expr); and then not need to set query.where()
            }
        };