Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
521 views
in Technique[技术] by (71.8m points)

java - Specification/Predicate to Search Nested Objects

I'm using Spring Boot with Spring JPA and Specification Executor. I have my Specification/Predicate combo successfully searching the simple attributes within my class. However, I am having difficulties searching the objects within. Do they need a separate Specification? I have a class that has 2 Many To One mapping classes within and would like to search those fields from within the same class.

Predicate Implementation

public Specification<User> getSpecification(SpecificationField field, Object searchCriteria){
    return new Specification<User>() {
    @Override
    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

    if(searchCriteria instanceof String){
        searchCriteria.toString().trim().toLowerCase();
    }

    switch(field){
    case USER_GROUP:    
        return cb.equal(cb.lower(root.<String> get("group").get("name")), searchCriteria);
    case USER_ROLE: 
        return cb.equal(cb.lower(root.<String> get("role").get("name")), searchCriteria);
    case USER_EMAIL: 
        return cb.equal(cb.lower(root.<String> get("email")), searchCriteria);
    case USER_FIRSTNAME: 
        return cb.equal(cb.lower(root.<String> get("firstName")), searchCriteria);
    case USER_LASTNAME: 
        return cb.equal(cb.lower(root.<String> get("lastName")), searchCriteria);
    case USER_USERNAME: 
        return cb.equal(cb.lower(root.<String> get("username")), searchCriteria);
    default:
        assert true;
        return null;
    }

User Class

@Id
@GeneratedValue
@Column(name = "USER_ID")
private Long id;

@Column(name = "USER_FIRSTNAME", nullable = false)
private String firstName;

@Column(name = "USER_LASTNAME", nullable = false)
private String lastName;

@Column(name = "USER_EMAIL", nullable = false, unique = true)
private String email;

@Column(name = "USER_USERNAME", nullable = false, unique = true)
private String username;

@Column(name = "USER_PASSWORD", nullable = false)
private String encryptedPassword;

@ManyToOne
@JoinColumn(name = "USER_ROLE", nullable = false)
private Role role;

@ManyToOne
@JoinColumn(name = "USER_GROUP", nullable = false)
private Group group;

Role Class

@Id
@GeneratedValue
@Column(name = "ROLE_ID")
private Long id;

@Column(name = "ROLE_NAME", nullable = false, unique = true)
private String name;

Group Class

@Id
@GeneratedValue
@Column(name = "GROUP_ID")
private Long id;

@Column(name = "GROUP_NAME", nullable = false, unique = true)
private String name;

@Column(name = "GROUP_TOKEN", nullable = false, unique = true)
private String token;

--------------------------------------------------------------------------

EDIT:

Came up with this Predicate implementation for the nested objects.

Root<Group> group = query.from(Group.class);
Root<Role> role = query.from(Role.class);

switch(field){
case USER_GROUP:
    return cb.equal(cb.lower(group.<String> get("name")), searchCriteria);
case USER_ROLE: 
    return cb.equal(cb.lower(role.<String> get("name")), searchCriteria);

This is working better, but not great. I have the possible group name values of DEV, UAT, or PROD. If I give any of these I get all the Users in my Database. If I don't I don't get any Users back. How can I do a text search on the name of this nested object?

Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I found the answer myself, but wanted to share with everybody so that it may help other people with the same issue.

@Override
public Predicate toPredicate(Root<User> userRoot, CriteriaQuery<?> query, CriteriaBuilder cb) {

    switch(field){
    case USER_GROUP:
        Join<User, Group> groupJoin = userRoot.join("group");
        return cb.equal(cb.lower(groupJoin.<String> get("name")), searchCriteria);
    case USER_ROLE: 
        Join<User, Role> roleJoin = userRoot.join("role");
        return cb.equal(cb.lower(roleJoin.<String> get("name")), searchCriteria);

Using the Join class from the javax.persistence library I could search the nested objects within my class with the same Specification.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...