Spring Data Mongo Repository:所有Repo共享的常用方法问题

6

用例

我正在尝试使用Spring Data MongoDB的向所有存储库添加自定义行为功能。

文档不提供有关如何使用JPA进行连接的有用信息。无论如何,我已经使用Mongo相当的配置完成了设置。

我想为所有实体添加一个findByCategoryName(String categoryName)方法,因为我的所有实体都将具有类别。类别是一个DBRef对象,因此必须使用自定义查询。

以下是相关配置的部分内容:

<!-- Activate Spring Data MongoDB repository support -->
<mongo:repositories base-package="com.domain.*.repo" repository-impl-postfix="CustomImpl" 
    factory-class="com.domain.commonrepo.CommonMongoRepoFactoryBean"/>

<bean id="mappingContext" class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />

<mongo:mapping-converter mapping-context-ref="mappingContext">
    <mongo:custom-converters base-package="com.domain.mongo.converter" />
</mongo:mapping-converter>

<bean id="entityInformationCreator" class="org.springframework.data.mongodb.repository.support.DefaultEntityInformationCreator">
    <constructor-arg name="mappingContext" ref="mappingContext" />
</bean>

FactoryBean

工厂Bean
    @NoRepositoryBean
    public class CommonMongoRepoFactoryBean<T extends MongoRepository<?,?>, ID extends        
    Serializable> extends MongoRepositoryFactoryBean{

@Autowired
private static MongoTemplate mongoTemplate;

protected MongoRepositoryFactory getRepositoryFactory(Class<T> clazz) {
    return new CommonMongoRepoFactory(clazz);
}

private static class CommonMongoRepoFactory extends MongoRepositoryFactory {
    private Class clazz;

    public CommonMongoRepoFactory(Class clazz) {
        super(mongoTemplate);
        this.clazz = clazz;
    }

    public CommonMongoRepoImpl getTargetRepository() {
        return new CommonMongoRepoImpl(clazz);
    }

    public Class<?> getRepositoryClass() {
        return CommonMongoRepoImpl.class;
    }
}

我知道这有点取巧,但没有文档真的很麻烦。如果有人知道更好的方法,请给我一个GitHub链接:-)
常见仓库接口
    @NoRepositoryBean
    public interface CommonMongoRepo<T, ID extends Serializable> extends MongoRepository<T,ID> {

public List<T> findByCategoryName(String categoryName);        

实现

    @NoRepositoryBean
    public class CommonMongoRepoImpl<T, ID extends Serializable> extends SimpleMongoRepository<T,    
    ID> implements CommonMongoRepo<T, ID> {

private Class<T> type;

@Autowired
private static MongoTemplate mongoOperations;

@Autowired
private static EntityInformationCreator entityInformationCreator;

@Autowired
private CategoryRepo categoryRepo;

public CommonMongoRepoImpl(Class<T> type) { 
    super((MongoEntityInformation<T, ID>) entityInformationCreator.getEntityInformation(type), mongoOperations);
}

@Override
public List<T> findByCategoryName(String categoryName) {

    Category category = categoryRepo.findByName(categoryName);

    return mongoOperations.find(query(where("categories.$id").is(category.getId())), type);
}

问题

现在,当我尝试使用通用方法时,我遇到了一个异常。

“实体”中没有找到属性“类别”,我想这是当mongo repo尝试自动实现该方法时发生的。尽管我声明该bean为@NoRepositoryBean,但仍然出现此问题。

请帮忙!!!不想将相同的自定义方法添加到所有实体中。


参考文档使用JPA 作为示例,因为我们不想为每个存储库重写常见的存储库文档。 因此,如果您将所有与Spring Data JPA相关的类型替换为相应的Spring Data MongoDB类型(JpaRepository-> MongoRepository等),则应该没问题。对不存在的文档进行抱怨真的没有帮助(尤其是如果它确实存在)。 如果您真的关心,您可以随时提交拉取请求以改进文档。 您介意同时发布具体的存储库接口声明以及存储库基类实现吗? - Oliver Drotbohm
1
谢谢您的回复。已经更新了代码问题。我正在阅读Spring-Data-Mongo文档,因此期望那里会有一个Mongo示例。而且,不仅仅是我,其他人也发现这个特定的示例非常难以实现>> https://dev59.com/1WHVa4cB1Zd3GeqPrONv - Nishant
2个回答

9

以下是最佳解决方案!

步骤一:
在接口中添加自定义方法!
增加一个自定义的方法

#自定义接口

/**
 * Basic Repository for common custom methods
 * @author liangping
 */

import java.io.Serializable;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;

@NoRepositoryBean
public interface WootideRepositoryCustom <T, ID extends Serializable>
      extends PagingAndSortingRepository<T, ID>, MongoRepository<T, ID> {

      public Page<T> search(Query query, Pageable pageable);
}

实现

第二步:
为你的自定义方法添加实现!
Add implement for your custom method!

/**
 * implement for wootide basic repository
 * @author liangping
 */

import java.io.Serializable;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;

public class WootideRepositoryImpl<T, ID extends Serializable> extends
        SimpleMongoRepository<T, ID> implements WootideRepositoryCustom<T, ID> {

    public WootideRepositoryImpl(MongoEntityInformation<T, ID> metadata,
            MongoOperations mongoOperations) {
        super(metadata, mongoOperations);
    }

    @Override
    public Page<T> search(Query query, Pageable pageable) {
        long total = this.getMongoOperations().count(query, this.getEntityInformation().getJavaType() );
        return new PageImpl<T>(this.getMongoOperations().find(query.with(pageable), this.getEntityInformation().getJavaType()), pageable, total);
    }

}

创建一个自定义仓库的新工厂。
/**
 * Repository Factory for all Subrepository
 * @author liangping
 */

import java.io.Serializable;

import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.MappingMongoEntityInformation;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;

public class WootideRepositoryFactoryBean<R extends MongoRepository<T, I>, T, I extends Serializable>
        extends MongoRepositoryFactoryBean<R, T, I> {

    @Override
    protected RepositoryFactorySupport getFactoryInstance(
            MongoOperations operations) {
        return new WootideMongoRepositoryFactory<T,I>( operations );
    }

    private static class WootideMongoRepositoryFactory<T, ID extends Serializable>
            extends MongoRepositoryFactory {

        private MongoOperations mongo;
        public WootideMongoRepositoryFactory(MongoOperations mongoOperations) {
            super(mongoOperations);
            this.mongo = mongoOperations;
        }

        @SuppressWarnings("unchecked")
        protected Object getTargetRepository(RepositoryMetadata metadata) {

            TypeInformation<T> information =  ClassTypeInformation.from((Class<T>)metadata.getDomainType());
            MongoPersistentEntity<T> pe = new BasicMongoPersistentEntity<T>(information);
            MongoEntityInformation<T,ID> mongometa = new MappingMongoEntityInformation<T, ID>(pe);

            return new WootideRepositoryImpl<T, ID>( mongometa,  mongo);
        }

        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return WootideRepositoryCustom.class;
        }
    }
}

使其正常运作
<mongo:repositories base-package="com.***.mongodb" 
factory-class="com.***.mongodb.custom.WootideRepositoryFactoryBean"/>

Good Luck! 祝你好运!


MongoRepository already extends PagingAndSortingRepository - syd
如何使用注释指定工厂类?谢谢 - ChambreNoire
1
如果只想让可用存储库的子集具有这些共享方法,怎么办?那是否排除了使用base-package的可能性? - ChambreNoire

-1

有点延迟,但这里是一个Spring Web应用程序项目的示例代码。要点如下:

  1. 在控制器中使用接口
  2. 在一个继承自基类的单独类中实现
  3. 基础实现提供了通用方法,任何其他控制器只需快速继承即可使用

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