Java Criteria API:在具有继承用户权限的树中查找实体
我试图使用CriteriaAPI在位置的层次结构中执行相当复杂的搜索 我在这里只写相关实体及其相关属性 实体 位置Java Criteria API:在具有继承用户权限的树中查找实体,java,spring,jpa,criteria,Java,Spring,Jpa,Criteria,我试图使用CriteriaAPI在位置的层次结构中执行相当复杂的搜索 我在这里只写相关实体及其相关属性 实体 位置 -Location-upperLocation(可能为空) -设置childrenLocation(可能为空) -设置管理器(可能为空) 警报 -源于的位置(可能为空) 使用者 更多详细信息 用户和位置之间的关系有很多种 位置表示是分层的。例如,世界是一个包含美国、英国、法国等国家的位置,这些国家本身包含城市 树中可以有无限级别的子位置 警报是否起源于某个位置 如果用户有效地(在数
-
Location-upperLocation
(可能为空)-
设置childrenLocation
(可能为空)-
设置管理器
(可能为空)
警报-
源于的位置(可能为空)
使用者
更多详细信息
用户和位置之间的关系有很多种
位置表示是分层的。例如,世界是一个包含美国、英国、法国等国家的位置,这些国家本身包含城市
树中可以有无限级别的子位置
警报是否起源于某个位置
如果用户有效地(在数据库中)管理某个位置,或者他是树中某个位置的父节点的管理者,则该用户被视为该位置的管理者。基本上,如果你是美国的经理,你会自动被认为是美国所有儿童场所的经理,以及他们的孩子,等等
我试图构建的标准必须查找源自某个位置的警报,该位置的用户要么是直接经理,要么是继承的经理
代码
我有一把刀:
AlertRepository扩展了JpaRepository,JpaSpecificationExecutor
我请求查询,只是传递规范
List alerts=dao.findAll(buildSpecificationForUser(user))
以及规范生成器:
private Specification<Alert> buildSpecificationForUser(final User user) {
return new Specification<Alert>() {
@Override
public Predicate toPredicate(Root<Alert> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
query.distinct(true);
Expression<Collection<User>> managersOfLocations = root.get("originatedIn").get("managers");
return builder.isMember(user, managersOfLocations);
}
};
}
用户专用规范BuildSpecification(最终用户){
返回新规范(){
@凌驾
公共谓词toPredicate(根根、CriteriaQuery查询、CriteriaBuilder){
query.distinct(true);
表达式managersOfLocations=root.get(“originatedIn”).get(“managers”);
返回builder.isMember(用户、管理员位置);
}
};
}
使用此功能,我只会收到用户直接管理的位置的警报
问题
如何使其在用户作为继承管理者的位置也能找到警报
更新
我也试过这个:
Join<Alert, User> managersOfLocation = root.join("originatedIn").join("upperLocation",JoinType.LEFT).join("managers",JoinType.LEFT);
return builder.equal(managersOfLocation.get("id"),user.getId());
Join managersOfLocation=root.Join(“originatedIn”).Join(“upperLocation”,JoinType.LEFT)。Join(“managers”,JoinType.LEFT);
返回builder.equal(managersOfLocation.get(“id”)、user.getId();
但是,如果用户不是任何位置的管理员,则结果集将返回所有警报事件,因为位置的表示是分层的,所以您将需要一个来获取所需的数据。但是,中没有直接的分层查询支持。如果你希望有很多地点,你就必须这样做 如果您不会有大量的位置,或者修改表结构现在不是一个选项,那么您可以创建一个视图来执行分层SQL,并映射到该视图。例如: 如果创建以下视图
manager\u location\u all
(在PostgreSQL 9.4.4上测试):
然后,您可以使用该视图将
Set allManagers
映射添加到位置对象,然后在规范生成器中执行root.get(“originatedIn”).get(“allManagers”)
。但是,这种方法的可扩展性不如更新数据模型。有一个类似的问题,但还没有得到回答,不走运:非常完整的答案我会研究一下。非常感谢。
CREATE OR REPLACE VIEW manager_location_all AS
WITH RECURSIVE ancestor_descendant(ancestor_id, descendant_id) AS (
SELECT root.upper_location_id, root.location_id
FROM location root
UNION ALL
SELECT l.upper_location_id, ad.descendant_id
FROM location l
JOIN ancestor_descendant ad ON l.location_id = ad.ancestor_id
)
SELECT manager_location.manager_id, ancestor_descendant.descendant_id AS location_id
FROM ancestor_descendant
JOIN manager_location ON ancestor_descendant.ancestor_id = manager_location.location_id
UNION ALL
SELECT manager_location.manager_id, manager_location.location_id
FROM manager_location;