Criteria API:使用继承的用户权限查找树中的实体

时间:2015-07-08 14:06:49

标签: java spring jpa criteria

我正在尝试使用条件API在位置的层次结构中执行相当复杂的搜索。

我只在这里写相关实体及其相关属性

实体

位置
- Set<User> managers(可能为空)
- Location originatedIn(可能是空的)
- AlertRepository extends JpaRepository<Alert, Long>, JpaSpecificationExecutor<Alert>(可能为空)

警报
- List<Alert> alerts = dao.findAll(buildSpecificationForUser(user))(可能为空)

用户

更多详情

用户和位置之间的关系是ManyToMany。

位置表示是分层的。例如,世界是一个包含美国,英国,法国的国家,它们本身包含城市,......

树中可以有无限级别的子位置。

警报是否来自某个位置。

如果用户有效(在数据库中)经理或者他是树中某个位置父母的经理,则该用户被视为某个位置的经理。基本上,如果您是美国的经理,您自动被视为美国所有儿童所在地的经理,以及他们的孩子等...

我正在尝试构建的标准必须找到源自用户是直接经理或继承经理的位置的警报。

代码

我有一个DAO:
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); } }; }
我请求查询,只是传递规范。

Join<Alert, User> managersOfLocation = root.join("originatedIn").join("upperLocation",JoinType.LEFT).join("managers",JoinType.LEFT); return builder.equal(managersOfLocation.get("id"),user.getId());

规范构建器:

UPDATE table SET field = CASE LENGTH(field)
    WHEN 7 THEN substr(field, 1, 2) || '-' || substr(field 3, 4) || '-' || substr(field, 7)
    WHEN 6 THEN (ANOTHER HANDLER FOR STRING WITH 6 CHAR )

END CASE;

使用此功能,我只能获得用户直接作为其经理的位置的警报。

问题

如何制作它以便在用户是继承经理的位置找到警报?

更新

我也试过这个:

GrupoMatricula

但是,如果用户不是任何位置的经理,则结果集会返回所有警报事件

1 个答案:

答案 0 :(得分:1)

由于Location的表示是分层的,因此您需要hierarchical query来获取所需的数据。但是,JPA 2.1中没有直接的分层查询支持。如果您希望有很多地点,则必须update your data model to use materialized paths or nested sets

如果你不会拥有大量的Locations,或者现在不能修改你的表结构,你可以创建一个为你做分层SQL的视图,然后映射到那个。例如:

如果您创建以下视图manager_location_all(在PostgreSQL 9.4.4上测试):

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;

然后,您可以使用该视图向Location对象添加Set<User> allManagers映射,然后在规范构建器中执行root.get("originatedIn").get("allManagers")。但是,这种方法不会像更新数据模型那样具有可扩展性。