Java 弹簧数据:默认值';未删除';使用软删除策略时基于方法的自动查询逻辑
假设我们使用软删除策略:不从存储中删除任何内容;相反,记录/文档/任何内容的“deleted”属性/列设置为true以使其“deleted”。稍后,查询方法只应返回未删除的条目 让我们以MongoDB为例(alghough JPA也很有趣) 对于由Java 弹簧数据:默认值';未删除';使用软删除策略时基于方法的自动查询逻辑,java,spring-data-jpa,spring-data,spring-data-mongodb,Java,Spring Data Jpa,Spring Data,Spring Data Mongodb,假设我们使用软删除策略:不从存储中删除任何内容;相反,记录/文档/任何内容的“deleted”属性/列设置为true以使其“deleted”。稍后,查询方法只应返回未删除的条目 让我们以MongoDB为例(alghough JPA也很有趣) 对于由MongoRepository定义的标准方法,我们可以扩展默认实现(simplemonogrepository),覆盖感兴趣的方法并使它们忽略“已删除”文档 但是,当然,我们也希望使用自定义查询方法,如 List<Person> findB
MongoRepository
定义的标准方法,我们可以扩展默认实现(simplemonogrepository
),覆盖感兴趣的方法并使它们忽略“已删除”文档
但是,当然,我们也希望使用自定义查询方法,如
List<Person> findByFirstName(String firstName)
列出findByFirstName(字符串名)
在软删除环境中,我们被迫执行以下操作
List<person> findByFirstNameAndDeletedIsFalse(String firstName)
列出FindByFirstName和DeleteDisFalse(字符串名)
或者使用@Query
手动编写查询(始终添加关于“未删除”的相同样板条件)
问题来了:是否可以将此“未删除”条件自动添加到任何生成的查询中?我在文档中没有找到任何东西
我在看Spring数据(Mongo和JPA)2.1.6
类似问题
@Where
注释,该注释仅适用于JPA+Hibernate,如果在某些查询中仍然需要访问已删除的项目,则不清楚如何覆盖它@的方法,要么解决方案的适用性受限于已经定义的标准方法,而不是自定义方法
事实证明,对于Mongo(至少对于spring data Mongo 2.1.6),我们可以侵入标准的
QueryLookupStrategy
实现,添加所需的“软删除文档不被查找者的行为看到”:
public class SoftDeleteMongoQueryLookupStrategy implements QueryLookupStrategy {
private final QueryLookupStrategy strategy;
private final MongoOperations mongoOperations;
public SoftDeleteMongoQueryLookupStrategy(QueryLookupStrategy strategy,
MongoOperations mongoOperations) {
this.strategy = strategy;
this.mongoOperations = mongoOperations;
}
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
NamedQueries namedQueries) {
RepositoryQuery repositoryQuery = strategy.resolveQuery(method, metadata, factory, namedQueries);
// revert to the standard behavior if requested
if (method.getAnnotation(SeesSoftlyDeletedRecords.class) != null) {
return repositoryQuery;
}
if (!(repositoryQuery instanceof PartTreeMongoQuery)) {
return repositoryQuery;
}
PartTreeMongoQuery partTreeQuery = (PartTreeMongoQuery) repositoryQuery;
return new SoftDeletePartTreeMongoQuery(partTreeQuery);
}
private Criteria notDeleted() {
return new Criteria().orOperator(
where("deleted").exists(false),
where("deleted").is(false)
);
}
private class SoftDeletePartTreeMongoQuery extends PartTreeMongoQuery {
SoftDeletePartTreeMongoQuery(PartTreeMongoQuery partTreeQuery) {
super(partTreeQuery.getQueryMethod(), mongoOperations);
}
@Override
protected Query createQuery(ConvertingParameterAccessor accessor) {
Query query = super.createQuery(accessor);
return withNotDeleted(query);
}
@Override
protected Query createCountQuery(ConvertingParameterAccessor accessor) {
Query query = super.createCountQuery(accessor);
return withNotDeleted(query);
}
private Query withNotDeleted(Query query) {
return query.addCriteria(notDeleted());
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SeesSoftlyDeletedRecords {
}
除非@SeesSoftlyDeletedRecords
要求避免,否则我们只需在所有查询中添加'and not deleted'条件
然后,我们需要以下基础结构来插入我们的querylikupstrategy
实现:
public class SoftDeleteMongoRepositoryFactory extends MongoRepositoryFactory {
private final MongoOperations mongoOperations;
public SoftDeleteMongoRepositoryFactory(MongoOperations mongoOperations) {
super(mongoOperations);
this.mongoOperations = mongoOperations;
}
@Override
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(QueryLookupStrategy.Key key,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
Optional<QueryLookupStrategy> optStrategy = super.getQueryLookupStrategy(key,
evaluationContextProvider);
return optStrategy.map(this::createSoftDeleteQueryLookupStrategy);
}
private SoftDeleteMongoQueryLookupStrategy createSoftDeleteQueryLookupStrategy(QueryLookupStrategy strategy) {
return new SoftDeleteMongoQueryLookupStrategy(strategy, mongoOperations);
}
}
public class SoftDeleteMongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
extends MongoRepositoryFactoryBean<T, S, ID> {
public SoftDeleteMongoRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
@Override
protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) {
return new SoftDeleteMongoRepositoryFactory(operations);
}
}
如果需要动态确定特定存储库是需要“软删除”还是需要常规“硬删除”存储库,我们可以反省存储库接口(或域类),并决定是否需要更改QueryLookupStrategy
对于JPA,如果不在PartTreeJpaQuery
中重写(可能重复)大部分代码,这种方法就无法工作
@EnableMongoRepositories(repositoryFactoryBeanClass = SoftDeleteMongoRepositoryFactoryBean.class)