【问题标题】:Spring JPA Specification. Join query in order to find userSpring JPA 规范。加入查询以查找用户
【发布时间】:2020-07-08 09:38:28
【问题描述】:

我有两张桌子:

@Table(name = "userinstance")
@Entity
public class UserInstance implements Comparable<UserInstance> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    @Size(min = 1, max = 100)
    @Column(length = 100, unique = false, nullable = false)
    private String uuid;

    @NotNull
    @Size(min = 1, max = 100)
    @Column(length = 100, unique = false, nullable = false)
    String userId;

    @NotNull
    @Size(min = 1, max = 100)
    @Column(length = 100, unique = false, nullable = false)
    private String name;

    @NotNull
    @Size(min = 1, max = 2048)
    @Column(length = 2048, unique = false, nullable = false)
    private String description;

    @JsonBackReference
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "userInstance")
    private List<UserDetailsInstance> userDetailsInstances = new ArrayList<>();

}
@Table(name = "userdetailsinstance")
@Entity
public class UserDetailsInstance implements Comparable<UserDetailsInstance> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    @Size(min = 1, max = 100)
    @Column(length = 100, unique = false, nullable = false)
    private String uuid;

    @JsonManagedReference
    @ManyToOne
    @JoinColumn(name = "usr_instance_id", nullable = false)
    private UserInstance userinstance;

    @NotNull
    @Size(min = 1, max = 100)
    @Column(length = 100, unique = false, nullable = false)
    private String name;

    @NotNull
    @Size(min = 1, max = 100)
    @Column(length = 100, unique = false, nullable = false)
    private String type;

    @Column(length = 1)
    private Status status;

    @Column(length = 1000)
    private String message;

    @Column(length = 4000)
    private String instanceData;

}

我想要实现的是能够使用过滤器并仅使用单个查询参数(“名称”)找到用户(UserInstance 表);

为了做到这一点,我有一个:

public class UserInstanceQuery extends BaseQuery {

    private final Long id;

    private final String name;

    private final String user;

    private final Instant createdDate;

    private final Instant lastModifiedDate;

    public UserInstanceQuery(Long id, String name, String user, String createdDate, String lastModifiedDate, Pageable pageable) {
        super(pageable);
        this.id = id;
        this.name = name;
        this.user = user;
        this.createdDate = convertStringToInstant(createdDate);
        this.lastModifiedDate = convertStringToInstant(lastModifiedDate);
    }
    
    public Specification<UserInstance> toSpecification() {
        return new UserSpecification(this);
    }
}

规范看起来像:

public class UserInstanceSpecification implements Specification<UserInstance> {

    private final UserInstanceQuery userInstanceQuery;

    @Override
    public Predicate toPredicate(Root<UserInstance> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> predicates = new LinkedList<>();

        if (userInstanceQuery.getId() != null) {
            predicates
                .add(
                    cb.equal(root.get("id"),
                        userInstanceQuery.getId())
                );
        }

        if (userInstanceQuery.getUser() != null && !userInstanceQuery.getUser().isEmpty()) {
            predicates
                .add(cb.equal(
                    cb.lower(root.get("userId")), userInstanceQuery.getUser().toLowerCase()));
        }

        if (userInstanceQuery.getName() != null && !userInstanceQuery.getName().isEmpty()) {
            Subquery<UserInstance> subquery = query.subquery(UserInstance.class);
            Root<UserDetailsInstance> subRoot = subquery.from(UserDetailsInstance.class);
            List<Predicate> subPredicates = new ArrayList<>();
            subPredicates.add(cb.like(subRoot.get("instanceData"), "%" + userInstanceQuery.getName() + "%"));

            subquery.select(subRoot.get("userInstance")).where(subPredicates.toArray(new Predicate[predicates.size()]));

            predicates.add(
                cb.or(
                    cb.like(cb.lower(root.get("name")), "%" + userInstanceQuery.getName().toLowerCase() + "%"),
                    cb.like(cb.lower(root.get("environment")), "%" + userInstanceQuery.getName().toLowerCase() + "%"),
                    cb.like(cb.lower(root.get("description")), "%" + userInstanceQuery.getName().toLowerCase() + "%"),
                    cb.exists(subquery)
                )
            );
        }

        if (userInstanceQuery.getCreatedDate() != null && userInstanceQuery.getLastModifiedDate() != null) {
            predicates.add(
                cb.and(
                    cb.greaterThanOrEqualTo(root.get("createdDate"), userInstanceQuery.getCreatedDate()),
                    cb.lessThanOrEqualTo(root.get("lastModifiedDate"), userInstanceQuery.getLastModifiedDate())
                )
            );
        }

        return cb.and(predicates.toArray(new Predicate[predicates.size()]));
    }

    private boolean currentQueryIsCountRecords(CriteriaQuery<?> criteriaQuery) {
        return criteriaQuery.getResultType() == Long.class || criteriaQuery.getResultType() == long.class;
    }
}

问题是,当我搜索仅包含在 UserDetailsInstance "instanceData" 字段中的字符串时,我会得到多个结果,这些结果实际上并没有我需要的数据,也不是指用户

Hibernate 生成这样的 sql:

select user0_.id as id1_7_, user0_.created_by as created_by2_7_, user0_.created_date as created_date3_7_, user0_.last_modified_by as last_modified_by4_7_, user0_.last_modified_date as last_modified_date5_7_, user0_.version as version6_7_, user0_.description as description7_7_, user0_.environment as environment8_7_, user0_.name as name9_7_, user0_.user_id as user_id10_7_, user0_.uuid as uuid11_7_ from usertinstance user0_ 
where (lower(user0_.name) like ?
 or lower(user0_.environment) like ? 
 or lower(user0_.description) like ? 
 or exists (select userdetail.tds_instance_id 
      from userdetailsinstance userdetail 
      cross join usertinstance user2_ 
          where userdetail.tds_instance_id=user2_.id 
      and (userdetail.instance_data like ?))) 
  and user0_.created_date>=? and user0_.last_modified_date<=? order by user0_.id desc fetch first ? rows only

如果我尝试在 SQLDeveloper/Datagrip 中运行此查询,我还会得到一组多行 同时如果我改变(第 8 行)

where userdetail.usr_instance_id=user2_.id 

where userdetail.usr_instance_id=user0_.id 

我得到了我需要的结果

能否请您指出查询创建中的错误,或者告诉我如何使此查询返回我需要的值

谢谢!

【问题讨论】:

    标签: spring spring-boot spring-data-jpa


    【解决方案1】:

    解决方案比我预期的要容易得多

    用户实例规范:

    if (userInstanceQuery.getName() != null && !userInstanceQuery.getName().isEmpty()) {
                Join<UserInstance, UserDetailsInstance> bos = root.join("userDetailsInstances", JoinType.LEFT);
    
                predicates.add(
                    cb.or(
                        cb.like(cb.lower(root.get("name")), "%" + userInstanceQuery.getName().toLowerCase() + "%"),
                        cb.like(cb.lower(root.get("description")), "%" + userInstanceQuery.getName().toLowerCase() + "%"),
                        cb.like(cb.lower(bos.get("instanceData")), "%" + userInstanceQuery.getName().toLowerCase() + "%")
                    )
                );
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-14
      • 2018-07-22
      • 1970-01-01
      • 2017-01-12
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多