【发布时间】:2017-03-08 15:39:53
【问题描述】:
以下实体的引用情况:
Collision -> CollisionStatus CollisionWorkgroup(加入实体)-> 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:(感兴趣的类别,见下文)
@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:(在CollisionStatus 和Workgroup 之间连接实体/表,PK=[CollisionStatusId, ClientId],两者都输入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:(加入实体PK类)
@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:(其实不是很有趣,只是用来比较条件查询中的clientId)
@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 连接工作组。
这意味着,每个客户端都可以将一个工作组与冲突的状态实体关联起来。每个登录到系统的用户只能从其客户端看到一个(每个用户都属于一个客户端),但其他用户在 UI 上不可见。
按原样执行查询时,多个客户端设置工作组的任何冲突状态都会在我们的数据表/查询结果中产生额外的结果。
这是有道理的,所以我需要向查询中添加一些自定义谓词以仅生成与当前用户的客户端 ID 相关联的条目。显示其他客户的条目是错误的。
我在 SO 上找到了这个:
Using JPA CriteriaBuilder to generate query where attribute is either in a list or is empty
我试过代码:
@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<?>>
显然,问题在于Map 不是Collection 的子类。
问:
如何使用 Criteria API 在 JPA 中测试空的 Map?
【问题讨论】:
标签: java hibernate jpa eclipselink jpql