【问题标题】:QueryDslMongoRepository ProjectionQueryDsl MongoRepository 投影
【发布时间】:2013-12-29 15:05:51
【问题描述】:

我正在使用带有 querydsl 的 mongodb 的 spring-data。 我有一个仓库

public interface DocumentRepository extends MongoRepository<Document, String> ,QueryDslPredicateExecutor<Document> {}

和一个实体

@QueryEntity
public class Document {

private String id;
private String name;
private String description;
private boolean locked;
private String message;

}

我需要加载包含 id 和 name 信息的文档列表。 所以只有 id 和 name 应该在我的实体中加载和设置。 我认为查询投影是正确的词。 支持吗?

另外我需要实现一些延迟加载逻辑。 存储库中是否有类似“跳过”和“限制”的功能?

【问题讨论】:

    标签: mongodb spring-data querydsl


    【解决方案1】:

    投影

    据我所知,默认 Spring Data 存储库不支持投影。如果您想确保只有投影从数据库发送到您的应用程序(例如,出于性能原因),您必须自己实现相应的查询。将自定义方法添加到标准 repo 的扩展中应该不会太费力。

    如果您只想对调用您的应用程序的某些客户端隐藏某些字段的内容,您通常会使用另一组实体对象,并在两者之间进行适当的映射。对不同级别的详细信息使用相同的 POJO 总是令人困惑,因为您将不知道一个字段是否实际上是 null 或者该值是否只是在特定上下文中被抑制。

    分页

    我目前无法测试任何代码,但根据QueryDslPredicateExecutor 的文档,findAll(predicate, pageable) 方法应该是你想要的:

    • 它返回一个Page 对象,它是您的Document 的常规Iterable
    • 您必须将其传递给 Pageable,例如使用PageRequest;为已知的 skip 和 limit 值初始化它应该是微不足道的

    【讨论】:

    • 确实支持投影,看我的回答。
    【解决方案2】:

    这有很多方面,因为它 - 不幸的是 - 不是一个问题,而是多个问题。

    对于投影,您可以简单地使用@Query 注释的fields 属性:

    interface DocumentRepository extends MongoRepository<Document, String>, QuerydslPredicateExecutor<Document> {
    
      @Query(value = "{}", fields = "{ 'id' : 1, 'name' : 1 }")
      List<Document> findDocumentsProjected();
    }
    

    您可以将其与查询派生机制(通过不设置query)、分页(见下文)甚至返回子句中的专用投影类型(例如,DocumentExcerpt 与只有id 和@ 987654328@ 字段)。

    存储库抽象完全支持分页。通过扩展基本接口,您已经获得了findAll(Pageable) 和该方法的 Querydsl 特定版本。您还可以在 finder 方法中使用分页 API,添加 Pageable 作为参数并返回 Page

    Page<Document> findByDescriptionLike(String description, Pageable pageable)
    

    reference documentation 中查看更多信息。

    【讨论】:

    • 有没有办法使用repository.findAll?
    【解决方案3】:

    我也为 JPA 找到了这种方法

    Spring Data JPA and Querydsl to fetch subset of columns using bean/constructor projection

    我目前正在尝试为 MongoDB 实现此功能。

    【讨论】:

      【解决方案4】:

      根据这个答案 -> Question

      实体

      @QueryEntity
      public class Document extends AbstractObject {
      }
      

      自定义 QuerydslMongoRepository

      public interface CustomQuerydslMongoRepository<T extends AbstractObject,ID extends Serializable> extends MongoRepository<T, ID> ,QueryDslPredicateExecutor<T>{
          Page<T> findAll(Predicate predicate, Pageable pageable,Path... paths);
          Page<T> findAll(Predicate predicate, Pageable pageable,List<Path> projections);
      
      }
      

      自定义 QuerydslMongoRepository 实现

      public class CustomQuerydslMongoRepositoryImpl<T extends AbstractObject,ID extends Serializable> extends QueryDslMongoRepository<T,ID> implements CustomQuerydslMongoRepository<T,ID> {
      
          //All instance variables are available in super, but they are private
          private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
      
      
          private final EntityPath<T> path;
          private final PathBuilder<T> pathBuilder;
          private final MongoOperations mongoOperations;
          public CustomQuerydslMongoRepositoryImpl(MongoEntityInformation<T, ID> entityInformation, MongoOperations mongoOperations) {
              this(entityInformation, mongoOperations,DEFAULT_ENTITY_PATH_RESOLVER);
          }
      
          public CustomQuerydslMongoRepositoryImpl(MongoEntityInformation<T, ID> entityInformation, MongoOperations mongoOperations, EntityPathResolver resolver) {
              super(entityInformation, mongoOperations, resolver);
              this.path=resolver.createPath(entityInformation.getJavaType());
              this.pathBuilder = new PathBuilder<T>(path.getType(), path.getMetadata());
              this.mongoOperations=mongoOperations;
          }
      
          @Override
          public Page<T> findAll( Predicate predicate, Pageable pageable,Path... paths) {
              Class<T> domainType = getEntityInformation().getJavaType();
              MongodbQuery<T> query = new SpringDataMongodbQuery<T>(mongoOperations, domainType);
              long total = query.count();
              List<T> content = total > pageable.getOffset() ? query.where(predicate).list(paths) : Collections.<T>emptyList();
              return new PageImpl<T>(content, pageable, total);
          }
      
          @Override
          public Page<T> findAll(Predicate predicate, Pageable pageable, List<Path> projections) {
              Class<T> domainType = getEntityInformation().getJavaType();
              MongodbQuery<T> query = new SpringDataMongodbQuery<T>(mongoOperations, domainType);
              long total = query.count();
              List<T> content = total > pageable.getOffset() ? query.where(predicate).list(projections.toArray(new Path[0])) : Collections.<T>emptyList();
              return new PageImpl<T>(content, pageable, total);
          }
      }
      

      自定义存储库工厂

      public class CustomQueryDslMongodbRepositoryFactoryBean<R extends QueryDslMongoRepository<T, I>, T, I extends Serializable> extends MongoRepositoryFactoryBean<R, T, I> {
      
      
          @Override
          protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) {
              return new CustomQueryDslMongodbRepositoryFactory<T,I>(operations);
          }
      
          public static class CustomQueryDslMongodbRepositoryFactory<T, I extends Serializable> extends MongoRepositoryFactory {
              private MongoOperations operations;
      
              public CustomQueryDslMongodbRepositoryFactory(MongoOperations mongoOperations) {
                  super(mongoOperations);
                  this.operations = mongoOperations;
              }
      
      
              @SuppressWarnings({ "rawtypes", "unchecked" })
              protected Object getTargetRepository(RepositoryMetadata metadata) {
                      return new CustomQuerydslMongoRepositoryImpl(getEntityInformation(metadata.getDomainType()), operations);
                }
      
              protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
                  return CustomQuerydslMongoRepository.class;
              }
          }
      }
      

      实体存储库

      public interface DocumentRepository extends CustomQuerydslMongoRepository<Document, String>{
      
      }
      

      在服务中的使用

      @Autowired
      DocumentRepository repository;
      
      public List<Document> getAllDocumentsForListing(){
      return repository.findAll(  QDocument.document.id.isNotEmpty().and(QDocument.document.version.isNotNull()), new PageRequest(0, 10),QDocument.document.name,QDocument.document.version).getContent();
      }
      

      【讨论】:

      • 这完全不需要。详情请见我的answer
      猜你喜欢
      • 2020-07-05
      • 2021-03-22
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      • 2021-11-14
      • 2018-11-05
      • 2021-08-27
      • 2016-03-01
      相关资源
      最近更新 更多