使用规范进行深度联接

时间:2019-11-04 14:49:51

标签: hibernate jpa spring-data-jpa dsl criteria-api

我的实体A与实体B的关系为1-1。
实体B与实体C的关系为1-1。

  • UserEntity
    • BadgeEntity
      • BadgeTypEntity

我要使用“规范”实现复杂的过滤搜索。 此外,我将JOIN FETCH配置为从UserEntity到BadgeEntity,从BadgeEntity到BadgeTypEntity,以便在单个查询中检索带有“ BadgeType”的UserEntity。

没有规格,直接使用标准API,很容易解决在需要的地方配置所需提取的问题。

我首先尝试: https://github.com/tkaczmarzyk/specification-arg-resolver#enabling-spec-annotations-in-your-spring-app 但似乎只能配置一个级别的提取(UserEntity-> BadgeEntity)

因此,我尝试提供一个“伪”规范,该规范只是向查询中添加了所需的JOIN FETCH,但是我认为这很难使它正常工作。

用户实体

public class UserEntity
{

   private String name;
   private String email;  

   @Fetch(FetchMode.JOIN)
   @OneToOne(fetch = FetchType.EAGER)
   @JoinColumn(name = "BADGE_ID")
   private BadgeEntity badge;

   ...
}

徽章实体

public class BadgeEntity
{

    @Fetch(FetchMode.JOIN)
    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "BADGE_TYPE_ID")
    private BadgeTypeEntity badgeType;
  ...
}

BadgeType实体

public class BadgeTypeEntity
{

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name = "BADGE_TYPE_ID")
    private Integer badgeTypeId;

    @Column(name = "CODE")
    private String code;
}

电子邮件过滤器规范

public class UsersEmailSpec implements Specification<UserEntity>
{

    private String email;

    public UsersEmailSpec(String email)
    {
        this.email = email;
    }

    @Override
    public Predicate toPredicate(Root<UserEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)
    {
        Predicate result = null;
        if(StringUtils.isNotEmpty(this.email))
        {
            result = criteriaBuilder.like(root.get(UserEntity_.email),this.email);
        }
        return result;
    }
}

NAME过滤器规范

public class UsersNameSpec implements Specification<UserEntity>
{

    private String name;

    public UsersNameSpec(String name)
    {
        this.name = name;
    }

    @Override
    public Predicate toPredicate(Root<UserEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)
    {
        Predicate result = null;
        if(StringUtils.isNotEmpty(this.name))
        {
            result = criteriaBuilder.like(root.get(UserEntity_.name),this.name);
        }
        return result;
    }
}

用于配置FETCH JOIN的FAKE规范

Specification conjunctionSpec = new Specification() {
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
        Fetch fetch = root.fetch(UserEntity_.badge, JoinType.INNER).fetch(BadgeEntity_.badgeType, JoinType.INNER);
            return null;
    }
};

是否有办法使用“规范”巧妙地解决此问题?

1 个答案:

答案 0 :(得分:0)

您可以实现多级实体子映射。

示例:

criteriaBuilder.like(root.get("badge").get("badgeType").get("email"),this.email);