项目使用JPA开发,现有两个实体(表),一个是通用的权限实体(表)DataRelation,一个是业务实体(表)MachDropEvent,由于权限表管理了很多不同的业务实体的数据权限,所以在实体上,并不想建立属性关系。但查询数据时,要通过DataRelation来限制查询MachDropEvent。
权限实体结构如下
@Data
@Entity
@Table(name = "ri_base_data_relation")
public class DataRelation extends CreatOnlyAuditable {
@Id
private Long id;
private String dataType; //数据类名,如:RiskEvent
private String dataId; //数据ID,如RiskEvent.id
private String userId; //关联的用户ID
private String orgId; //关联的组织部门ID
}
业务实体如下:
@Data
@Entity
@Table(name = "iot_mach_gps_drop_event")
public class MachDropEvent
private Long id;
... 其它属性
@OneToOne
private RiskEvent riskEvent;`
}
使用JPQL就很简单了,
from MachOfflineEvent me join riskEvent as re join DataRelation dr on cast(re.id as text) = dr.dataId and dr.dataType = 'RiskEvent' and dr.userId = :userId
注意:由于权限表中数据ID为通用的String类型,而业务表中的ID为Long型,所以要转型:cast(re.id as text)
使用Criteria/Predicate的代码如下:
Root<MachDropEvent> root;
CriteriaQuery<?> query;
CriteriaBuilder criteriaBuilder;
if (finalRelaUser != null) {
Join<Object, Object> riskEvent = root.join("riskEvent");
Subquery<DataRelation> subquery = query.subquery(DataRelation.class);
Root<DataRelation> subroot = subquery.from(DataRelation.class);
Predicate userPredicate = criteriaBuilder.equal(subroot.get("userId"), finalRelaUser);
Predicate typePredicate = criteriaBuilder.equal(subroot.get("dataType"), RiskEvent.class.getSimpleName());
Predicate dataId = criteriaBuilder.equal(subroot.get("dataId"), riskEvent.get("id").as(String.class));
predicates.add(criteriaBuilder.exists(subquery.select(subroot).where(userPredicate, dataId, typePredicate)));
}
这样产生的sql使用exists子查询语句,和上面的jpql产生的join不太一样,但效果相同。