Tôi đang sử dụng QueryDslPredicateExecutor
từ dự án JPA dữ liệu mùa xuân và tôi đang phải đối mặt với nhu cầu mong muốn tìm nạp mối quan hệ lười biếng. Tôi biết rằng tôi có thể sử dụng truy vấn JPA-QL nguyên gốc trong giao diện Repository, hoặc thậm chí sử dụng JPAQLQuery từ DSL truy vấn, nhưng tôi bị hấp dẫn nếu điều này thậm chí có thể để tạo điều kiện truy vấn xây dựng cho các nhu cầu trong tương lai.Có cách nào háo hức tìm kiếm mối quan hệ lười biếng thông qua API Predicate trong QueryDSL không?
Trả lời
Tôi gặp sự cố tương tự khi tôi phải tìm nạp một Bộ sưu tập trong khi sử dụng Predicates và QueryDslPredicateExecutor.
Điều tôi đã làm là tạo triển khai kho lưu trữ tùy chỉnh để thêm phương thức cho phép tôi xác định các thực thể sẽ được tìm nạp.
Đừng để bị nản lòng bởi số lượng mã ở đây, nó thực sự rất đơn giản và bạn sẽ cần phải làm rất ít thay đổi để sử dụng nó trên ứng dụng của bạn
Đây là giao diện của tùy chỉnh kho
@NoRepositoryBean
public interface JoinFetchCapableRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {
Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors);
}
JoinDescriptor
public class JoinDescriptor {
public final EntityPath path;
public final JoinType type;
private JoinDescriptor(EntityPath path, JoinType type) {
this.path = path;
this.type = type;
}
public static JoinDescriptor innerJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.INNERJOIN);
}
public static JoinDescriptor join(EntityPath path) {
return new JoinDescriptor(path, JoinType.JOIN);
}
public static JoinDescriptor leftJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.LEFTJOIN);
}
public static JoinDescriptor rightJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.RIGHTJOIN);
}
public static JoinDescriptor fullJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.FULLJOIN);
}
}
Thực hiện các kho lưu trữ tùy chỉnh
public class JoinFetchCapableRepositoryImpl <T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> implements JoinFetchCapableRepository<T, ID> {
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private final EntityPath<T> path;
private final PathBuilder<T> builder;
private final Querydsl querydsl;
public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
}
public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver);
this.path = resolver.createPath(entityInformation.getJavaType());
this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
}
@Override
public Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors) {
JPQLQuery countQuery = createQuery(predicate);
JPQLQuery query = querydsl.applyPagination(pageable, createFetchQuery(predicate, joinDescriptors));
Long total = countQuery.count();
List<T> content = total > pageable.getOffset() ? query.list(path) : Collections.<T> emptyList();
return new PageImpl<>(content, pageable, total);
}
protected JPQLQuery createFetchQuery(Predicate predicate, JoinDescriptor... joinDescriptors) {
JPQLQuery query = querydsl.createQuery(path);
for(JoinDescriptor joinDescriptor: joinDescriptors)
join(joinDescriptor, query);
return query.where(predicate);
}
private JPQLQuery join(JoinDescriptor joinDescriptor, JPQLQuery query) {
switch(joinDescriptor.type) {
case DEFAULT:
throw new IllegalArgumentException("cross join not supported");
case INNERJOIN:
query.innerJoin(joinDescriptor.path);
break;
case JOIN:
query.join(joinDescriptor.path);
break;
case LEFTJOIN:
query.leftJoin(joinDescriptor.path);
break;
case RIGHTJOIN:
query.rightJoin(joinDescriptor.path);
break;
case FULLJOIN:
query.fullJoin(joinDescriptor.path);
break;
}
return query.fetch();
}
}
Factory để tạo ra các kho tùy chỉnh, thay thế mặc định QueryDslJpaRepository
public class JoinFetchCapableQueryDslJpaRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
extends JpaRepositoryFactoryBean<R, T, I> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new JoinFetchCapableQueryDslJpaRepositoryFactory(entityManager);
}
private static class JoinFetchCapableQueryDslJpaRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public JoinFetchCapableQueryDslJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new JoinFetchCapableRepositoryImpl<>(getEntityInformation(metadata.getDomainType()), entityManager);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return JoinFetchCapableRepository.class;
}
}
}
Bước cuối cùng là thay đổi cấu hình JPA để nó sử dụng nhà máy này thay vì mặc định:
<jpa:repositories base-package="com.mycompany.repository"
entity-manager-factory-ref="entityManagerFactory"
factory-class="com.mycompany.utils.spring.data.JoinFetchCapableQueryDslJpaRepositoryFactoryBean" />
Sau đó, bạn có thể sử dụng nó từ lớp dịch vụ của bạn như thế này:
public Page<ETicket> list(ETicketSearch eTicket, Pageable pageable) {
return eticketRepository.findAll(like(eTicket), pageable, JoinDescriptor.leftJoin(QETicket.eTicket.order));
}
Bằng cách sử dụng JoinDescriptor bạn sẽ có thể để xác định những gì bạn muốn tham gia dựa trên nhu cầu dịch vụ của bạn.
Tôi đã có thể thực hiện điều này nhờ phản hồi của Murali tại đây: Spring Data JPA and Querydsl to fetch subset of columns using bean/constructor projection Vui lòng xem qua.
Cảm ơn câu trả lời của bạn. Mặc dù tôi đã kết thúc làm việc với phương pháp Tiêu chí, tôi sẽ thử nghiệm phương pháp này trên một dự án nhỏ hơn mà tôi có để thử nghiệm các công cụ. Cảm ơn sự nỗ lực của bạn ... –
Xin chào, cảm ơn câu trả lời. Có thể mở rộng JoinDescriptor để bao gồm onetomany (tức là SetPath) thay vì chỉ EntityPath không? –
@AngelVillalain "Mặc dù tôi đã kết thúc làm việc với phương pháp Tiêu chí" - Bạn có thể giải thích cách bạn làm cho nó hoạt động không? – Pranjal
Dữ liệu mùa xuân has introduced JPA Entity Graph support. Hãy coi chừng đó là does not currently work with graphs that are traversed via EmbeddedIds.
Khi câu hỏi này được hỏi, không có sự hỗ trợ cho Biểu đồ thực thể JPA, nó vẫn đang được phát triển chính xác. Nhưng bây giờ mà điều này là có sẵn Tôi nghĩ rằng câu hỏi này nên xem xét điều này như là một giải pháp. –
- 1. Có thể tải lười biếng cho một mối quan hệ không lười biếng trong Hibernate không?
- 2. Grails/GORM mặc định chiến lược tìm nạp: Khi nào để đặt fetchMode thành "háo hức"? (háo hức và lười biếng)
- 3. NHibernate 3 thuộc tính lười biếng và truy vấn háo hức
- 4. Rails 3: Tải trọng lười biếng so với tải háo hức
- 5. cách tránh trùng lặp trong mối quan hệ has_many: thông qua mối quan hệ?
- 6. Grails: Làm thế nào tôi có thể tìm kiếm thông qua các trẻ em trong mối quan hệ hasMany?
- 7. Tìm kiếm trong mối quan hệ nhiều-nhiều với Doctrine2
- 8. Khi nào việc đánh giá lười biếng không hữu ích?
- 9. Tìm kiếm các mục theo mối quan hệ nhiều-nhiều
- 10. JPA: Tôi có nên lưu trữ BLOB trong cùng một bảng với tìm nạp Lười biếng hay tôi nên lưu trữ nó vào một bảng khác và tìm nạp một cách lười biếng mối quan hệ 1-1:
- 11. Rails 4 Không thể tìm thấy liên kết has_many, thông qua: lỗi mối quan hệ
- 12. Đánh giá lười biếng trong Ruby
- 13. Mã EF Lần đầu tiên háo hức tải
- 14. Vui lòng tải mối quan hệ đệ quy
- 15. NHibernate Háo hức tải đa cấp đối tượng trẻ em
- 16. psql: không tìm thấy mối quan hệ bất chấp quan hệ hiện có
- 17. LINQ to Entities - tải háo hức sử dụng Bao gồm()
- 18. NHibernate: Làm thế nào để háo hức tìm nạp thực thể phụ với một bộ lọc trên thực thể phụ thông qua một truy vấn sql mà không lười biếng?
- 19. Làm cách nào để xác định mối quan hệ Nhiều-với-Nhiều qua Khuôn khổ thực thể API thông thạo?
- 20. Hibernate: đặt nhiều mối quan hệ một-nhiều
- 21. Lazy/Háo hức tải/lấy trong Neo4j/mùa xuân-Data
- 22. Tìm hiểu các mối quan hệ và mối quan hệ dữ liệu của Orchard
- 23. django-tastypie: Đăng vào một lĩnh vực ManytoMany Resource có với thông qua mối quan hệ
- 24. SDWebImage hình ảnh tải háo hức
- 25. Làm thế nào để có mối quan hệ với một mối quan hệ luôn được nhúng
- 26. NSPredicate để tìm kiếm trong các thực thể mối quan hệ
- 27. NSPredicate to-many mối quan hệ
- 28. Mối quan hệ dữ liệu dưới dạng ngữ cảnh tìm kiếm trong Marklogic
- 29. Tìm kiếm dữ liệu cốt lõi cho tất cả các đối tượng có mối quan hệ "to-many" rỗng
- 30. lọc đối tượng trẻ em trong một has_many: thông qua mối quan hệ trong Rails 3
Ý của bạn là gì nếu điều này thậm chí có thể xảy ra? 'QueryDslPredicateExecutor' cung cấp một tập con nhỏ của chức năng Querydsl, để biết thêm bạn cần tự viết các truy vấn. –
Vâng, tôi biết điều đó, nhưng tôi đang cố nghĩ cách tránh điều đó và sử dụng API Predicate, để xây dựng các truy vấn phức tạp hơn, cho phép tôi tìm nạp các mối quan hệ theo ý muốn, nối thêm các vị từ khác, do đó không phải tạo phương thức với truy vấn được chú thích cho một mục đích cụ thể trong giao diện Kho lưu trữ. –