2015-09-30 9 views
8

मेरे पास User इकाई, UserToApplication इकाई, और Application इकाई है।स्प्रिंग डेटा जेपीए विशिष्टता CriteriaBuilder w/एक रिश्ते के लिए एक

एक एकल User एक से अधिक Application तक पहुंच सकता है। और एक Application का उपयोग एक से अधिक User द्वारा किया जा सकता है।

यहां User इकाई है।

@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 and setters omitted for brevity */ 
} 

यहां UserToApplication इकाई है।

@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; 
    } 
} 

और यहां Application इकाई है।

@Entity 
@Table(name = "APPLICATION", schema = "UDB") 
public class Application { 
    private Long applicationId; 
    private String name; 
    private String code; 

    /* Getters and setters omitted for brevity */ 
} 

मैं निम्नलिखित Specification कि मैं firstNm, lastNm, और email द्वारा एक User के लिए खोज करने के लिए उपयोग किया है।

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); 
      } 
     }; 
    } 

} 

और यहां User_ मेटामोडेल है जो अब तक है।

@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; 
} 

अब, मैं भी Specification के लिए आवेदन आईडी की एक सूची में पारित करने के लिए चाहते हैं, जैसे कि इसकी विधि हस्ताक्षर होगा:

public static Specification<User> findByFirstNmLastNmEmailApp(String firstNm, String lastNm, String email, Collection<Long> appIds) 

तो, मेरे सवाल है, मैं जोड़ सकते हैं @OneToManyUser_ मेटामोडेल Collection<Application> applications के लिए User इकाई के क्षेत्र में मैपिंग, और फिर मैं Specification में इसका संदर्भ कैसे दूंगा?

मेरे वर्तमान Specification निम्नलिखित SQL क्वेरी करने के समान होगा:

select * from user u 
where lower(first_nm) like '%firstNm%' 
and lower(last_nm) like '%lastNm%' 
and lower(email) like '%email%'; 

और क्या मैं नए Specification में प्राप्त करने के लिए कुछ इस तरह होगा चाहते हैं:

select * from user u 
join user_to_application uta on uta.user_id = u.user_id 
where lower(u.first_nm) like '%firstNm%' 
and lower(u.last_nm) like '%lastNm%' 
and lower(u.email) like '%email%' 
and uta.application_id in (appIds); 

क्या यह संभव है मेटामोडेल में इस प्रकार की मैपिंग करने के लिए, और मैं इस परिणाम को अपने Specification में कैसे प्राप्त कर सकता हूं?

उत्तर

11

मुझे एक समाधान मिला।

public static volatile CollectionAttribute<User, Application> applications; 

मैं भी Application इकाई के लिए एक मेटामॉडल जोड़ने के लिए की जरूरत: कई विशेषता किसी एक को मैप करने के लिए, मेटामॉडल में मैं निम्नलिखित गयी।

@StaticMetamodel(Application.class) 
public class Application_ { 
    public static volatile SingularAttribute<Application, Long> applicationId; 
} 
तब मेरे Specification में

, मैं एक उपयोगकर्ता के लिए applications एक्सेस कर सका, Root<User> उदाहरण पर .join() पद्धति का उपयोग करके। मैंने बनाया Predicate यहां दिया गया है।

final Predicate appPredicate = root.join(User_.applications).get(Application_.applicationId).in(appIds); 

इसके अलावा, यह ध्यान देने योग्य है कि मेरे Specification के रूप में यह प्रश्न में लिखा है काम नहीं करेगा अगर इनपुट मानों के किसी भी खाली हैं। PredicateCriteriaBuilder की विधि NullPointerException का कारण बन जाएगा। इसलिए, मैंने प्रकार Predicate का ArrayList बनाया, फिर संबंधित पैरामीटर गैर-खाली होने पर प्रत्येक Predicate को सूची में जोड़ा गया। अंत में, मैं CriteriaBuilder के .and() फ़ंक्शन को पास करने के लिए ArrayList को सरणी में परिवर्तित करता हूं। यहाँ अंतिम 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()])); 
      } 
     }; 
    } 

} 
+0

Application_ कक्षा में चर घोषणा के रूप में इस प्रकार है, सार्वजनिक स्थिर अस्थिर SingularAttribute होना चाहिए <आवेदन, लांग> applicationId; सार्वजनिक स्थैतिक अस्थिर सिंगुलरएट्रिब्यूट एप्लिकेशन आईडी के बजाय; कुल जवाब सही है हालांकि – Avi

+0

@Avi धन्यवाद यह इंगित करने के लिए! मैंने इसे अपने जवाब में सही कर दिया है। –

संबंधित मुद्दे