2015-09-30 28 views
8

User varlığım, UserToApplication öğesinin ve Application öğesinin var.Spring Data JPA Özelliği, çoktan fazlasına kadar Kriteri Oluşturucusu kullanarak

Tek bir User, birden fazla Application erişim hakkına sahiptir. Ve tek bir Application, birden fazla User tarafından kullanılabilir.

İşte User varlıkları.

@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 */ 
} 

İşte UserToApplication varlıkları.

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

Ve işte Application varlıktır.

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

    /* Getters and setters omitted for brevity */ 
} 

ben firstNm, lastNm ve email tarafından User aramak için kullandıkları Specification şu var. Burada

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

} 

Ve

var bugüne kadar User_ metamodel olduğunu.

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

Şimdi, aynı zamanda Specification uygulama kimlikleri bir listede geçmek istiyorum, böyle onun yöntem imzası olacağını:

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

Yani, benim sorum, ben ekleyebilir @OneToMany benim User varlığımın Collection<Application> applications alanı için User_ metamodel ile eşleme, ve sonra nasıl Specification içinde başvuruyor?

Benim şimdiki Specification aşağıdaki SQL sorgusuna benzer olacaktır:

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

Ve ne Böyle bir şey olacağını yeni Specification ulaşmak istiyorum: Mümkün

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

mi metamodelde bu tür bir haritalama yapmak için, ve bu sonucu benim Specification'uma nasıl ulaştırabilirim?

cevap

11

Bir çözüm buldum. Ben de Application varlık için bir Metamodel eklemek için gerekli

public static volatile CollectionAttribute<User, Application> applications; 

: Birçok özelliğe bir tane haritasını çıkarmak için, metamodel içinde aşağıdaki ekledi.

benim Specification yılında Sonra
@StaticMetamodel(Application.class) 
public class Application_ { 
    public static volatile SingularAttribute<Application, Long> applicationId; 
} 

, ben Root<User> örneğinde .join() yöntemini kullanarak, bir kullanıcı için applications erişebilir. İşte ben oluşturduğum Predicate.

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

Ayrıca, kayda değer olduğunu benim Specification o girdi değerlerden herhangi boşsa çalışmaz söz konusu yazıldığı gibi. CriteriaBuilder'un .and() yöntemine geçirilen Predicate numaralı boş bir NullPointerException neden olur. Bu nedenle, Predicate türünde bir ArrayList oluşturduktan sonra karşılık gelen parametre boş değilse listeye her bir Predicate ekledim. Son olarak, CriteriaBuilder'un .and() işlevine iletmek için ArrayList bir diziye dönüştürüyorum. İşte son Specification geçerli:

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

, kamu statik uçucu SingularAttribute şöyle Application_ sınıfında değişken ifadesi olmalıdır applicationID; public statik volatile SingularAttribute applicationId yerine; Genel cevap mükemmel olsa da – Avi

+0

@Avi bunu işaret ettiğin için teşekkürler! Cevabımda bunu düzelttim. –

İlgili konular