Spring boot JPA oneTomany 使用 FilterDef 过滤子集

· 如故 · 284阅读 · 2022-10-06

详细描述

JPA oneTomany 使用 FilterDef 过滤子集

版本信息

Spring Boot + Jpa

复现过程

在开发之中,经常会有表关联的情况,一对多,多对多,一对一等等。

Jpa中对这些关联情况给了完整的解决方案,使用oneToMany等注解,可以将关联关系安全的交给JPA管理。

在OneToMange的使用中,例如多级权限表。

public class Permission {

@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
@Column(columnDefinition = "varchar(32)")
private String id;

@CurdModel(value = "所属父级",isShow = false,isSearch = true,listUrl = "/permission/list",type = YueColumnsType.LIST)
private String parentId;

@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "parentId")
@JsonIgnoreProperties("children")
@Fetch(FetchMode.JOIN)
private Set<Permission> children=new HashSet<>();
}

表结构如上,多余字段已隐藏。

如果用户拥有权限1,2,3.

那么Jpa语法一般会使用in查询,但是这种情况会导致children不会被用户权限筛选,会被全部查出。

Jpa对子集筛选由@where注解,但是这个注解只能静态筛选,例如逻辑删除过滤已经删除的数据。

 

解决方案

后来查询到解决方案使用@FilterDef注解过滤

@FilterDef(name = "permissionChildren", parameters = {@ParamDef(name="ids",type="java.lang.String")})
public class Permission {

@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
@Column(columnDefinition = "varchar(32)")
private String id;

@CurdModel(value = "所属父级",isShow = false,isSearch = true,listUrl = "/permission/list",type = YueColumnsType.LIST)
private String parentId;

@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "parentId")
@JsonIgnoreProperties("children")
@Fetch(FetchMode.JOIN)
@Filter(name = "xxx", condition = " id in (:ids) ")
private Set<Permission> children=new HashSet<>();
}

在需要筛选的字段上使用@Filter标注,name根据业务起名即可,随便。condition是筛选语句,这里需要使用in语法,所以加了括号,:ids是参数,如果筛选已经删除的,可以直接写condition=“delete= 1”,动态参数使用【:参数名】的形式。

 

类上面标注@FilterDef, name根据业务起名,parameters 就是字段筛选参数,@ParamDef(name="ids",type="java.lang.String") 表示ids字段,类型为java.lang.String ,类型最好填全限定类名

 

这里说一下,正常情况下,需要填写类名,这里我使用的in语法,传入的是一个数组,理论上需要填写java.util.ArrayList才对,但是我这样填,后面给参数赋值,使用setParameter传递列表才行,这里比较坑,ArrayList完整写法应该是ArrayList<T>,这里的T属于未知类型,没办法序列化,最后给你弄成一个二进制字符串,查不出来。

最后使用时注入entityManager

@Autowired
@PersistenceContext()
EntityManager entityManager;

Session session = entityManager.unwrap(Session.class);
session.enableFilter("permissionChildren").setParameterList("ids",yueRole.getPermissionIds());//yueRole.getPermissionIds()只是我传入的一个数组,无需计较是什么
List<Permission>permissions=permissionRepository.findAll();
session.disableFilter("permissionChildren");

其实很简单,

查询之前开启过滤session.enableFilter("permissionChildren").setParameterList("ids",yueRole.getPermissionIds()),这里注意,我是使用的in查询,所以需要传递数组,正常传参使用setParameter即可

查询之后关闭过滤就行session.disableFilter("permissionChildren");

文章有用

已有 21人 推荐该文章,推荐越多越容易获得的官方扶持

微信扫码分享