【问题标题】:Spring Data QuerydslBinderCustomizer when no filter parameters are passed没有传递过滤器参数时的Spring Data QuerydslBinderCustomizer
【发布时间】:2018-09-28 08:27:06
【问题描述】:

我正在实现一个实现 QuerydslBinderCustomizer 的存储库,以帮助从 url 过滤器参数创建谓词。就是这样

@NoRepositoryBean
public interface TableRepository<T extends TableEntity, S extends EntityPathBase<T>> extends PagingAndSortingRepository<T, UUID>, QuerydslPredicateExecutor<T>, QuerydslBinderCustomizer<S> {
    @Override
    default void customize(@NonNull QuerydslBindings bindings, @NonNull S root) {
        bindings.bind(String.class).all((MultiValueBinding<StringPath, String>) (path, values) -> {
            BooleanBuilder predicate = new BooleanBuilder();
            values.forEach(value -> predicate.or(path.containsIgnoreCase(value)));
            return Optional.of(predicate);
        });
    }
}

我的个人实体存储库是从这个扩展而来的,

public interface UserRepository extends TableRepository<User, QUser> {
}

这会产生一个端点http://localhost:port/users。一切正常,我可以提出诸如http://localhost:port/users?name="somename" 之类的请求。

现在,我正在实施软删除,我不想在查询时返回软删除记录。我正计划为此编辑customize 方法

default void customize(@NonNull QuerydslBindings bindings, @NonNull S root) {
        bindings.bind(String.class).all((MultiValueBinding<StringPath, String>) (path, values) -> {
            BooleanBuilder predicate = new BooleanBuilder();
            values.forEach(value -> predicate.or(path.containsIgnoreCase(value)));
            // If path does not have delete flag, add deleted=false to the predicate
            return Optional.of(predicate);
        });
    }

但是当在没有任何参数的情况下调用端点时会出现问题,即http://localhost:port/users。在这种情况下,bindings.bind() 被执行,但BooleanBuilder predicate = new BooleanBuilder(); 部分未被执行。因此,我无法添加所需的谓词来过滤掉软删除的记录。如何进行?

我可能以错误的方式过滤已删除记录。有更好的选择吗?

编辑:根据要求,我正在链接一个基本存储库https://github.com/SayakMukhopadhyay/demo-querydsl

【问题讨论】:

  • 看起来您想覆盖 findAll() 方法以排除已删除的实体。您可以通过各种方式做到这一点。见这里:stackoverflow.com/a/29034847/1356423
  • 这是我尝试的第一件事。但似乎在实现 Querydsl 之后,CrudRepository findAll() 永远不会被调用。我尝试写@Override default Iterable&lt;T&gt; findAll(){ System.out.print("yo"); return null; },它不打印也不触发断点。
  • 通过答案中引用的其他选项尝试。
  • 我看不出任何答案如何为我的问题指明方向。我觉得我的问题是 querydsl 特有的,它不在链接答案的范围内。此外,我正在使用 spring-data-rest,因此我的存储库会自动链接到 REST 调用。因此,在我的存储库中创建自定义方法也不可行。
  • 是的,我非常清楚您在做什么 - 我可以阅读 (stackoverflow.com/tags/spring-data-rest/topusers)。我提到它是因为它概述了覆盖存储库的 findAll() 方法/查询的 3 种方法。如果没有指定参数(即不需要 QueryDSL 绑定),我希望对 SDR 框架的 REST 请求委托给 findAll() 但我可能错了。我向您推荐的答案提供了 3 种方法来覆盖为调用 findAll() 执行的查询(例如,附加条件以排除已删除)。

标签: spring-data spring-data-jpa spring-data-rest querydsl


【解决方案1】:

所以我想您现在已经找到了解决方案。 但对于那些试图获得某种“默认谓词”的人来说,这是一个潜在的解决方案。

就像您的情况一样,我们也进行了软删除,并希望在默认情况下排除它们,除非特别要求。

首先,您不能在自定义方法中设置此项。 这些绑定仅在为条件传递值时触发。由于某些原因,他们没有为没有价值的情况提供绑定。 他们可能有充分的理由这样做。 所以在这个方法中你只关心通过的标准。

我们在请求中处理默认值的方式是在调用 findAll 之前修改 Predicate。

控制器

Controller 签名应如下所示,带有谓词:

@GetMapping
public ResponseEntity<List<User>> searchUsers(
            @QuerydslPredicate(root = User.class, bindings = UserRepository.class) Predicate predicate) 

服务

您只需要检查谓词中是否包含条件, 如果没有,请自行添加。

if (!ExpressionUtils.extract(predicate).toString().contains("deleted =")) {
    predicate = new StringPath("deleted").eq("false").and(predicate);
}
userRepository.findAll(predicate);

如果不存在则应添加条件,如果存在则忽略。

这显然是一个简化的表示,但想法就在那里。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2015-05-23
    • 2023-03-11
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 2021-12-02
    • 2012-07-29
    相关资源
    最近更新 更多