JPA动态查询关联两个无关联的实体(表)Criteria/Predicate/JPQL

项目使用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不太一样,但效果相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值