JPA's complex multi-table queries

Recent work carried out only because the requirements for hibernate + jpa interact with the database, in a simple query, jpa inheritance CrudRepository interface, and then use jpa method naming specification jpql query, but when performing complex queries, need to inherit JpaSpecificationExecutor interface utilizes Specification for complex queries, since I myself have encountered this problem, check a lot of information, although there are ways, but do not have a detailed explanation to know that the method can not be good use jpa complex queries at convenience. I will give you a few chestnuts, detail of talk about my own use jpa multi-table queries complex scenes and ideas.

Chestnuts 1:

To a User entity class screened in several properties.

1. 名字
2. ID
3. 手机号

This condition is more than a single table of complex queries, because it is screened in several properties, the number of properties which do not know how many, so you only need to use Specification query can easily achieve this demand. See the code below:
Scene: Filter by conditions on the page, a list of user queries

There id 3 conditions on a page I set were searchName, searchId, searchMobile. Since this is a user table so userRepository inherited JpaSpecificationExecutor interfaces, then I created a package condition of class

public class PageParam<T> {
    private Integer pageSize = 10;
    private Integer pageNumber = 1;
    private String searchName;
    private String searchMobile;
    private String searchId;
}

Since this method is a direct I tab so pageNumber pageSize and may be written directly into this category, for facilitating reception parameter, primarily the encapsulation of the following three parameters

Specification<T> specification = new Specification<T>() {

    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> list = new ArrayList<Predicate>();

        if (StringUtils.isNotBlank(searchName)) {
            list.add(cb.like(root.get("name").as(String.class), "%" + searchName + "%"));
        }

        if (StringUtils.isNotBlank(searchId)) {
            list.add(cb.equal(root.get("id").as(Long.class), searchId));
        }

        if (StringUtils.isNotBlank(searchMobile)) {
            list.add(cb.like(root.get("mobile").as(String.class), "%" + searchMobile + "%"));
        }

        Predicate[] p = new Predicate[list.size()];
        return cb.and(list.toArray(p));
    };
};

Here is a table because, so long as the name root.get ( 'N') corresponding to the N to check the attributes of good, property name property name important things to say three times.
The next look at a set of multi-table queries

Chestnuts 2:

There are four tables

public class Living {
    Long id;
    
    @ManyToOne
    @JsonIgnore
    @JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT))
    public Actor actor;
    
   @ManyToOne
    @JsonIgnore
    @JoinColumn(name = "regionId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT))
    public Region region;
}
    
public class Actor {
    Long id;
    
    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
    @JoinColumn(name = "actorId")
    @org.hibernate.annotations.ForeignKey(name = "none")
    List<Living> livings = new ArrayList<>();
    
   @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
    @org.hibernate.annotations.ForeignKey(name = "none")
    @JoinColumn(name = "userDetailId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
    UserDetail userDetail;
    
   @Column(nullable = false)
    @Enumerated(value = EnumType.ORDINAL)
    ActorType actorType = ActorType.A;
    
    public enum ActorType{
        A,B,C
    }
}
    
public class UserDetail {
    Long id; 
    
   @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
    @org.hibernate.annotations.ForeignKey(name = "none")
    @JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
    Actor actor;
    
    String truename;
}
    
public class Region {
    Long id;
    
    String name;
    
    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
    @JoinColumn(name = "regionId")
    @org.hibernate.annotations.ForeignKey(name = "none")
    List<Living> Livings;
}
    

Now we want to check out living conditions to meet the conditions according to userdetai kinds of sex actor in the region as well as the id actortype.

public class PageParam<Living> {
    private Integer pageSize = 10;
    private Integer pageNumber = 1;
    private Sex sex;
    private ActorType actortype;
    private Long cityid;

First, I still encapsulates such a class, but generic here I was directly given to the generic query results you want, because this involves the following query more than one table so the example above single-table queries are no longer suitable this query, but the Criteria join method provides us with a model

Specification<Living> specification = new Specification<Living>() {

    @Override
    public Predicate toPredicate(Root<Living> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> list = new ArrayList<Predicate>();

        if (null!=sex) {
            Join<UserDetail, Living> join = root.join("actor", JoinType.LEFT);
            list.add(cb.equal(join.get("userDetail").get("sex"),  sex ));
        }

        if (null!=actortype) {
            Join<Actor, Living> join = root.join("actor", JoinType.LEFT);
            list.add(cb.equal(join.get("actorType"),  actortype));
        }
        if (null!=cityid) {
            Join<Region, Living> join = root.join("region", JoinType.LEFT);
            list.add(cb.equal(join.get("id"), cityid));
        }

        //Join<A, B> join = root.join("bs", JoinType.LEFT);
        //list.add(cb.equal(join.get("c").get("id"), id));
        Predicate[] p = new Predicate[list.size()];
        return cb.and(list.toArray(p));
    };
};

Here are my conditions of the package. multiple query conditions jpa method mainly based Criteria for the encapsulation conditions we provide, and according to the position defined conditions, and then generate sql statement, after the completion of the query.
I have to say the place in this multi-table queries in the following sentence as an example

Join<UserDetail, Living> join = root.join("actor", JoinType.LEFT);
list.add(cb.equal(join.get("userDetail").get("sex"),  sex ));

jointype.LEFT main point is that this property is in the final table, which, while in front of the "actor", said the first step of a query from the living query table, such as the example I give is to check out living in the actor then after the actor is sex in userdetail property userdetail in so the following join.get ( "userDetail"). get ( "sex"), this is get out of the corresponding attribute, up until you get the desired properties . The next two attributes are also the same token,
many people jpa has a great misconception that jpa multi-table, multi-complex query conditions, as mybatis query, before I also think so, but since achieved this by jpa after the multi-table queries and more complex conditions, I think it is not inferior to complex queries hibernate mybatis, especially sql statement is not very proficient code farmers, although a higher threshold may hibernate jpa hibernate just lowered the threshold needed to, I hope you It can more easily interact with the database through my experience.

Guess you like

Origin www.cnblogs.com/alterem/p/11295358.html