java - Spring Data JPA Specification using CriteriaBuilder w/ a one to many relationship -


i have user entity, usertoapplication entity, , application entity.

a single user can have access more 1 application. , single application can used more 1 user.

here user entity.

@entity @table(name = "user", schema = "udb") public class user {     private long userid;     private collection<application> applications;     private string firstnm;     private string lastnm;     private string email;      @sequencegenerator(name = "generator", sequencename = "udb.user_seq", initialvalue = 1, allocationsize = 1)     @id     @generatedvalue(strategy = generationtype.sequence, generator = "generator")     @column(name = "user_id", unique = true, nullable = false)     public long getuserid() {         return userid;     }      public void setuserid(long userid) {         this.userid = userid;     }      @onetomany(mappedby = "user", fetch = fetchtype.lazy)     public collection<application> getapplications() {         return applications;     }      public void setapplications(collection<application> applications) {         this.applications = applications;     }      /* other getters , setters omitted brevity */ } 

here usertoapplication entity.

@entity @table(name = "user_to_application", schema = "udb") public class application {     private long usertoapplicationid;     private user user;     private application application;      @sequencegenerator(name = "generator", sequencename = "udb.user_to_app_seq", initialvalue = 0, allocationsize = 1)     @id     @generatedvalue(strategy = generationtype.sequence, generator = "generator")     @column(name = "user_to_application_id", unique = true, nullable = false)     public long getusertoapplicationid() {         return usertoapplicationid;     }      public void setusertoapplicationid(long usertoapplicationid) {         this.usertoapplicationid = usertoapplicationid;     }      @manytoone     @joincolumn(name = "user_id", referencedcolumnname = "user_id", nullable = false)     public user getuser() {         return user;     }      public void setuser(user user) {         this.user = user;     }      @manytoone     @joincolumn(name = "application_id", nullable = false)     public application getapplication() {         return application;     } } 

and here application entity.

@entity @table(name = "application", schema = "udb") public class application {     private long applicationid;     private string name;     private string code;      /* getters , setters omitted brevity */ } 

i have following specification use search user firstnm, lastnm, , email.

public class userspecification {      public static specification<user> findbyfirstnmlastnmemail(string firstnm, string lastnm, string email) {         return new specification<user>() {             @override             public predicate topredicate(root<user> root, criteriaquery<?> query, criteriabuilder cb) {                 final predicate firstnmpredicate = null;                 final predicate lastnmpredicate = null;                 final predicate emailpredicate = null;                  if (!stringutils.isempty(firstnm)) {                     firstnmpredicate = cb.like(cb.lower(root.get(user_.firstnm), firstnm));                 }                 if (!stringutils.isempty(lastnm)) {                     lastnmpredicate = cb.like(cb.lower(root.get(user_.lastnm), lastnm));                 }                 if (!stringutils.isempty(email)) {                     emailpredicate = cb.like(cb.lower(root.get(user_.email), email));                 }                 return cb.and(firstnmpredicate, lastnmpredicate, emailpredicate);             }         };     }  } 

and here user_ metamodel have far.

@staticmetamodel(user.class) public class user_ {     public static volatile singularattribute<user, string> firstnm;     public static volatile singularattribute<user, string> lastnm;     public static volatile singularattribute<user, string> email; } 

now, pass in list of application ids specification, such method signature be:

public static specification<user> findbyfirstnmlastnmemailapp(string firstnm, string lastnm, string email, collection<long> appids) 

so, question is, can add @onetomany mapping user_ metamodel collection<application> applications field of user entity, , how reference in specification?

my current specification similar following sql query:

select * user u lower(first_nm) '%firstnm%' , lower(last_nm) '%lastnm%' , lower(email) '%email%'; 

and achieve in new specification this:

select * user u join user_to_application uta on uta.user_id = u.user_id lower(u.first_nm) '%firstnm%' , lower(u.last_nm) '%lastnm%' , lower(u.email) '%email%' , uta.application_id in (appids); 

is possible kind of mapping in metamodel, , how achieve result in specification?

i found solution. map 1 many attribute, in metamodel added following:

public static volatile collectionattribute<user, application> applications; 

i needed add metamodel application entity.

@staticmetamodel(application.class) public class application_ {     public static volatile singularattribute<user, long> applicationid; } 

then in specification, access applications user, using .join() method on root<user> instance. here predicate formed.

final predicate apppredicate = root.join(user_.applications).get(application_.applicationid).in(appids); 

also, worth noting specification written in question not work if of input values empty. null predicate passed .and() method of criteriabuilder cause nullpointerexception. so, created arraylist of type predicate, added each predicate list if corresponding parameter non-empty. finally, convert arraylist array pass .and() function of criteriabuilder. here final specification:

public class userspecification {      public static specification<user> findbyfirstnmlastnmemailapp(string firstnm, string lastnm, string email, collection<long> appids) {         return new specification<user>() {             @override             public predicate topredicate(root<user> root, criteriaquery<?> query, criteriabuilder cb) {                 final collection<predicate> predicates = new arraylist<>();                 if (!stringutils.isempty(firstnm)) {                     final predicate firstnmpredicate = cb.like(cb.lower(root.get(user_.firstnm), firstnm));                     predicates.add(firstnmpredicate);                 }                 if (!stringutils.isempty(lastnm)) {                     final predicate lastnmpredicate = cb.like(cb.lower(root.get(user_.lastnm), lastnm));                     predicates.add(lastnmpredicate);                 }                 if (!stringutils.isempty(email)) {                     final predicate emailpredicate = cb.like(cb.lower(root.get(user_.email), email));                     predicates.add(emailpredicate);                 }                 if (!appids.isempty()) {                     final predicate apppredicate = root.join(user_.applications).get(application_.applicationid).in(appids);                     predicates.add(apppredicate);                 }                  return cb.and(predicates.toarray(new predicate[predicates.size()]));             }         };     }  } 

Comments

Popular posts from this blog

1111. appearing after print sequence - php -

java - WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/board/] in DispatcherServlet with name 'appServlet' -

Ruby on Rails, ActiveRecord, Postgres, UTF-8 and ASCII-8BIT encodings -