QueryDslMongoRepository 投影查询

3

我正在使用Spring Data和QueryDSL来操作MongoDB。我有一个仓库。

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和名称信息的文档列表。因此,只有id和名称应该被加载并设置到我的实体中。我认为查询投影是正确的术语。这个功能支持吗?

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

4个回答

3

这个问题有很多方面需要考虑,因为它不仅仅是一个问题,而是多个问题。

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

interface DocumentRepository extends MongoRepository<Document, String>, QuerydslPredicateExecutor<Document> {

  @Query(value = "{}", fields = "{ 'id' : 1, 'name' : 1 }")
  List<Document> findDocumentsProjected();
}

您可以将此与查询推导机制结合使用(不设置query),与分页(见下文)甚至在返回子句中使用专用的投影类型(例如仅具有idname字段的DocumentExcerpt)。
分页完全支持存储库抽象。通过扩展基本接口,您已经获得了findAll(Pageable)和Querydsl特定版本的方法。您还可以在查找器方法中使用分页API,添加Pageable作为参数并返回Page
Page<Document> findByDescriptionLike(String description, Pageable pageable)

有关更多信息,请参见参考文档


1
有没有办法使用repository.findAll? - user1955934

1

投影

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

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

分页

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

  • 它返回一个Page对象,该对象是您的Document的常规Iterable
  • 您需要为其传递一个Pageable,您可以使用PageRequest来获取; 对于已知的skip和limit值进行初始化应该很简单

投影确实得到支持,详见我的回答。 - Oliver Drotbohm

0
根据这个答案 -> 问题 <- 我实现了以下解决方案。 实体
@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();
}

这完全不必要。有关详细信息,请参阅我的答案 - Oliver Drotbohm

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接