gpt4 book ai didi

java - Spring 数据 : default 'not deleted' logic for automatic method-based queries when using soft-delete policy

转载 作者:太空宇宙 更新时间:2023-11-04 09:40:23 24 4
gpt4 key购买 nike

假设我们使用软删除策略:存储中不会删除任何内容;相反,在记录/文档/任何内容上将“已删除”属性/列设置为 true 以使其“已删除”。稍后,查询方法应仅返回未删除的条目。

让我们以 MongoDB 为例(虽然 JPA 也很有趣)。

对于 MongoRepository 定义的标准方法,我们可以扩展默认实现 (SimpleMongoRepository),覆盖感兴趣的方法并使它们忽略“已删除”文档。

但是,当然,我们也想使用自定义查询方法,例如

List<Person> findByFirstName(String firstName)

在软删除环境中,我们被迫做类似的事情

List<person> findByFirstNameAndDeletedIsFalse(String firstName)

或使用@Query手动编写查询(始终添加有关“未删除”的相同样板条件)。

问题来了:是否可以将这个“未删除”条件自动添加到任何生成的查询中?我在文档中没有找到任何内容。

我正在查看 Spring Data(Mongo 和 JPA)2.1.6。

类似问题

  1. Query interceptor for spring-data-mongodb for soft deletions在这里,他们建议使用 Hibernate 的 @Where 注释,该注释仅适用于 JPA+Hibernate,如果您仍然需要在某些查询中访问已删除的项目,目前尚不清楚如何覆盖它
  2. Handling soft-deletes with Spring JPA在这里,人们要么建议相同的基于 @Where 的方法,要么解决方案的适用性仅限于已定义的标准方法,而不是自定义方法。

最佳答案

事实证明,对于 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 要求避免它。

然后,我们需要以下基础设施来插入我们的 QueryLiikupStrategy 实现:

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);
}
}

然后我们只需要在 @EnableMongoRepositories 注释中引用工厂 bean,如下所示:

@EnableMongoRepositories(repositoryFactoryBeanClass = SoftDeleteMongoRepositoryFactoryBean.class)

如果需要动态确定特定存储库是否需要“软删除”或常规“硬删除”存储库,我们可以内省(introspection)存储库接口(interface)(或域类)并决定是否需要更改QueryLookupStrategy

对于 JPA,如果不重写(可能复制)PartTreeJpaQuery 中的大部分代码,这种方法就不起作用。

关于java - Spring 数据 : default 'not deleted' logic for automatic method-based queries when using soft-delete policy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56061498/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com