JPA CriteriaBuilder to generate a query when a Map is empty using @MapKeyColumn

After summarizing the situation of entities:

Collision → CollisionStatus ↔ CollisionWorkgroup (object merging) → Workgroup

Collision.java:

@Entity
@Table( name = "..." )
public class Collision
{
    ...

    @OneToOne( fetch = FetchType.EAGER, optional = false )
    @JoinColumn( name = "CSSTATE_ID", referencedColumnName = "CSSTATE_ID" )
    private CollisionStatus collisionStatus;

    ...
}

CollisionStatus.java: (interest class, see below)

@Entity
@Table( name = "..." )
public class CollisionStatus
{
    ...

    // THIS IS THE MAPPING OF INTEREST:
    @OneToMany( mappedBy = "collisionStatus", fetch = FetchType.LAZY )
    @MapKeyColumn( name = "CLIENT_ID", insertable = false, updatable = false )
    private Map<Long, CollisionWorkgroup> collisionWorkgroups;

    ...
}

CollisionWorkgroup.java: (attach an entity / table between CollisionStatusand Workgroup, with PK = [CollisionStatusId, ClientId], both types Long)

@Entity
@Table( name = "..." )
public class CollisionWorkgroup
{
    @EmbeddedId
    protected CollisionWorkgroupEmbeddedPK pk;

    @MapsId( "collisionStatusId" )
    @JoinColumn( name = "CSSTATE_ID", referencedColumnName = "CSSTATE_ID" )
    private CollisionStatus     collisionStatus;

    @MapsId( "clientId" )
    @ManyToOne
    @JoinColumn( name = "CLIENT_ID", referencedColumnName = "CLIENT_ID" )
    private Client              client;

    @ManyToOne( fetch = FetchType.LAZY, optional = false )
    @JoinColumn( name = "WORKGROUP_ID", referencedColumnName = "WORKGROUP_ID" )
    private Workgroup           workgroup;

    ...
}

CollisionWorkgroupEmbeddedPK.java: (connect PK class object)

@Embeddable
public class CollisionWorkgroupEmbeddedPK implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Column( name = "CSSTATE_ID" )
    private Long              collisionStatusId;

    @Column( name = "CLIENT_ID" )
    private Long              clientId;

    ...
}

Workgroup.java : (actually not very interesting, just used to compare clientId in query criteria)

@Entity
@Table( name = "..." )
public class Workgroup
{
    @Column( name = "CLIENT_ID", insertable = false, updatable = false )
    private Long              clientId;

    @ManyToOne( fetch = FetchType.EAGER, optional = false )
    @JoinColumn( name = "CLIENT_ID", referencedColumnName = "CLIENT_ID" )
    private Client            client;

    ...
}

CollisionStatus CollisionWorkgroup @MapKeyColumn.

, . , , ( ), .

as-is , , /.

, , . .

SO:

JPA CriteriaBuilder , ,

:

@Override
protected List<Predicate> createCustomPredicates( CriteriaBuilder builder, From<?, ?> root )
{
    List<Predicate> predicates = new ArrayList<>();

    Long clientId = this.sessionHelper.getCurrentClientId();
    Join<Collision, CollisionStatus> collisionStatus = root.join( "collisionStatus" );
    MapJoin<CollisionStatus, Long, CollisionWorkgroup> collisionWorkgroups = collisionStatus.<CollisionStatus, Long, CollisionWorkgroup>joinMap( "collisionWorkgroups", JoinType.LEFT );
    predicates.add( builder.and( builder.or( builder.isEmpty( collisionWorkgroups ),
                                             builder.equal( collisionWorkgroups.<String>get( "workgroup" ).<String>get( "clientId" ), clientId ) ) ) );

    ...
}

builder.isEmpty(, :

Bound mismatch: The generic method isEmpty(Expression<C>) of type CriteriaBuilder
is not applicable for the arguments (MapJoin<CollisionStatus,Long,CollisionWorkgroup>).
The inferred type CollisionWorkgroup is not a valid substitute for the bounded
parameter <C extends Collection<?>>

, , a Map Collection.

:

Map JPA, API- Criteria?

+4
1

, . JPA IS_EMPTY Collection API . - CriteriaBuilder JPA CriteriaBuilder.

, JPA :

// existing method
<C extends Collection<?>> Predicate isEmpty(Expression<C> collection);
// overload
<C extends Map<?>> Predicate isEmpty(Expression<C> map);

JPQL .

+2

Source: https://habr.com/ru/post/1658914/


All Articles