【问题标题】:Integrating Query dsl with Reactive Mongo Repository in spring 5在 Spring 5 中将 Query dsl 与 Reactive Mongo Repository 集成
【发布时间】:2017-09-02 15:46:40
【问题描述】:

在我能够使用 QuerydslPredicateExecutor 扩展我的 mongo 存储库之前,Spring 5 为 spring data mongo 提供了一个响应式实现

 @Repository
 public interface AccountRepo extends MongoRepository<Account,String> 
 ,QuerydslPredicateExecutor<Account>

如果我试试这个

 @Repository
 public interface AccountRepo extends
 ReactiveMongoRepository<Account,String>,
 QuerydslPredicateExecutor<Account>

我的应用程序没有启动它,因为:

原因:org.springframework.data.mapping.PropertyReferenceException:找不到类型帐户的属性!

有没有办法解决这个问题

这里是账户类

package com.devop.models;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
@Data
public class Account {
@Id
String id;

String accountName;

String accountNumber;

String schemeCode;

String openDate;

String accountCategory;

String accountCurrency = "Naira";

String accountSecondaryCategory;

String receiveSmsAlert;

String recieveEmailAlert;

String cifId;

}

这里是AccountRepo界面

 package com.devop.mongoRepo;

 import com.devop.models.Account;
 import org.springframework.data.mongodb.repository.*;
 import org.springframework.data.mongodb.repository.support*;
 import org.springframework.data.querydsl.QuerydslPredicateExecutor;
 import org.springframework.stereotype.Repository;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;

 @Repository
 public interface AccountRepo extends 
 ReactiveMongoRepository<Account,String> 
 ,QuerydslPredicateExecutor<Account> {

Flux<Account> findAccountByAccountNameContains(String accountName);
Mono<Account> findAccountByAccountNumberEquals(String accountNumber);

}

【问题讨论】:

  • 共享 Account 类?
  • 帐号类已共享
  • 能分享一下AccountRepo的整个界面吗?
  • accountRepo 已共享
  • 响应式 MongoDB 存储库尚不支持 Querydsl。

标签: java spring mongodb reactive-programming


【解决方案1】:

您可以使用ReactiveQuerydslPredicateExecutor。有关更多信息,请参阅示例https://github.com/spring-projects/spring-data-examples/tree/master/mongodb/querydsl

【讨论】:

    【解决方案2】:

    我使用自定义 ReactiveMongoRepositoryFactoryBeanReactiveMongoRepositoryFactory 找到了 workaround solution,它可以帮助其他正在为此苦苦挣扎的人

    首先你需要在响应式注解中使用repositoryFactoryBeanClass。

    @EnableReactiveMongoRepositories(repositoryFactoryBeanClass = CustomReactiveMongoRepositoryFactoryBean.class)
    @Configuration
    public class ReactiveMongoDbHack {
    }
    

    CustomReactiveMongoRepositoryFactoryBean 类

    import org.springframework.data.mongodb.core.ReactiveMongoOperations;
    import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactoryBean;
    import org.springframework.data.repository.core.support.RepositoryFactorySupport;
    
    public class CustomReactiveMongoRepositoryFactoryBean extends ReactiveMongoRepositoryFactoryBean {
        public CustomReactiveMongoRepositoryFactoryBean(Class repositoryInterface) {
            super(repositoryInterface);
        }
    
        @Override
        protected RepositoryFactorySupport getFactoryInstance(ReactiveMongoOperations operations) {
            return new CustomReactiveMongoRepositoryFactory(operations);
        }
    }
    

    CustomReactiveMongoRepositoryFactory 类

    import static org.springframework.data.querydsl.QuerydslUtils.QUERY_DSL_PRESENT;
    
    public class CustomReactiveMongoRepositoryFactory extends ReactiveMongoRepositoryFactory {
    
        private static MongoOperations operations;
        private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
    
        public CustomReactiveMongoRepositoryFactory(ReactiveMongoOperations operations) {
        super(operations);
        this.mappingContext = operations.getConverter().getMappingContext();
        }
    
        //TODO Must set MongoOperations(MongoTemplate)
        public static void setOperations(MongoOperations operations) {
        CustomReactiveMongoRepositoryFactory.operations = operations;
        }
    
        @Override
        protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
    
        RepositoryComposition.RepositoryFragments fragments = RepositoryComposition.RepositoryFragments.empty();
    
        boolean isQueryDslRepository = QUERY_DSL_PRESENT
            && QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
    
        if (isQueryDslRepository) {
    
            MongoEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType(),
                metadata);
    
            fragments = fragments.append(RepositoryFragment.implemented(
                getTargetRepositoryViaReflection(QuerydslMongoPredicateExecutor.class, entityInformation, operations)));
        }
    
        return fragments;
        }
    
        private <T, ID> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass,
                                                                       @Nullable RepositoryMetadata metadata) {
    
        MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(domainClass);
        return MongoEntityInformationSupport.<T, ID> entityInformationFor(entity,
            metadata != null ? metadata.getIdType() : null);
        }
    
    }
    

    spring-data-mongodb复制的MongoEntityInformationSupport类

    import org.springframework.data.domain.Persistable;
    import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
    import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
    import org.springframework.data.mongodb.repository.support.MappingMongoEntityInformation;
    import org.springframework.lang.Nullable;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    
    /**
     * Support class responsible for creating {@link MongoEntityInformation} instances for a given
     * {@link MongoPersistentEntity}.
     *
     * @author Christoph Strobl
     * @author Mark Paluch
     * @since 1.10
     */
    final class MongoEntityInformationSupport {
    
        private MongoEntityInformationSupport() {}
    
        /**
         * Factory method for creating {@link MongoEntityInformation}.
         *
         * @param entity must not be {@literal null}.
         * @param idType can be {@literal null}.
         * @return never {@literal null}.
         */
        @SuppressWarnings("unchecked")
        static <T, ID> MongoEntityInformation<T, ID> entityInformationFor(MongoPersistentEntity<?> entity,
                                                                      @Nullable Class<?> idType) {
    
        Assert.notNull(entity, "Entity must not be null!");
    
        MappingMongoEntityInformation<T, ID> entityInformation = new MappingMongoEntityInformation<T, ID>(
            (MongoPersistentEntity<T>) entity, (Class<ID>) idType);
    
        return ClassUtils.isAssignable(Persistable.class, entity.getType())
            ? new PersistableMongoEntityInformation<>(entityInformation) : entityInformation;
        }
    }
    

    PersistableMongoEntityInformation 类也复制自spring-data-mongodb

    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;
    
    import org.springframework.data.domain.Persistable;
    import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
    
    /**
     * {@link MongoEntityInformation} implementation wrapping an existing {@link MongoEntityInformation} considering
     * {@link Persistable} types by delegating {@link #isNew(Object)} and {@link #getId(Object)} to the corresponding
     * {@link Persistable#isNew()} and {@link Persistable#getId()} implementations.
     *
     * @author Christoph Strobl
     * @author Oliver Gierke
     * @since 1.10
     */
    @RequiredArgsConstructor
    class PersistableMongoEntityInformation<T, ID> implements MongoEntityInformation<T, ID> {
    
        private final @NonNull MongoEntityInformation<T, ID> delegate;
    
        /*
         * (non-Javadoc)
         * @see org.springframework.data.mongodb.repository.MongoEntityInformation#getCollectionName()
         */
        @Override
        public String getCollectionName() {
        return delegate.getCollectionName();
        }
    
        /*
         * (non-Javadoc)
         * @see org.springframework.data.mongodb.repository.MongoEntityInformation#getIdAttribute()
         */
        @Override
        public String getIdAttribute() {
        return delegate.getIdAttribute();
        }
    
        /*
         * (non-Javadoc)
         * @see org.springframework.data.repository.core.EntityInformation#isNew(java.lang.Object)
         */
        @Override
        @SuppressWarnings("unchecked")
        public boolean isNew(T t) {
    
        if (t instanceof Persistable) {
            return ((Persistable<ID>) t).isNew();
        }
    
        return delegate.isNew(t);
        }
    
        /*
         * (non-Javadoc)
         * @see org.springframework.data.repository.core.EntityInformation#getId(java.lang.Object)
         */
        @Override
        @SuppressWarnings("unchecked")
        public ID getId(T t) {
    
        if (t instanceof Persistable) {
            return ((Persistable<ID>) t).getId();
        }
    
        return delegate.getId(t);
        }
    
        /*
         * (non-Javadoc)
         * @see org.springframework.data.repository.core.support.PersistentEntityInformation#getIdType()
         */
        @Override
        public Class<ID> getIdType() {
        return delegate.getIdType();
        }
    
        /*
         * (non-Javadoc)
         * @see org.springframework.data.repository.core.support.EntityMetadata#getJavaType()
         */
        @Override
        public Class<T> getJavaType() {
        return delegate.getJavaType();
        }
    }
    

    那么你的带有 Query DSL 的反应式存储库就可以工作了。

    public interface AssetRepository extends ReactiveCrudRepository<Asset, String>, QuerydslPredicateExecutor<Asset> {
    }
    

    PS:一定需要在CustomReactiveMongoRepositoryFactory.setOperations设置MongoOperations,我做的是使用Mongo的自动配置类(MongoAutoConfiguration和MongoDataAutoConfiguration)然后在方法中使用@PostConstruct来设置它。

    【讨论】:

      猜你喜欢
      • 2023-03-19
      • 2015-09-24
      • 1970-01-01
      • 2016-08-04
      • 2020-11-06
      • 2020-04-21
      • 2019-05-24
      • 1970-01-01
      • 2023-03-27
      相关资源
      最近更新 更多