Spring Data JDBC 动态的 where 子句

huangapple go评论80阅读模式
英文:

Spring Data JDBC dynamic where clauses

问题

  1. 有没有一种方法可以使用Spring Data JDBC编写动态的WHERE查询?

  2. 我如何访问底层的DataSource(或者也许是JdbcTemplate)以直接执行此查询?

例如:

  1. this.jdbcTemplate.query = query // 具有6个或更少的`WHERE`子句的动态查询;
  2. List<Result> results = this.jdbcTemplate.run();

谢谢!

编辑

有一个JdbcAggregateTemplate,带有一个<T> Iterable<T> findAll(Query query, Class<T> domainType); 查询。这是正确的地方吗?

与其他帖子相反,我无法自动装配EntityManager bean。

英文:

I have a custom search page, where i can enter up to 6 search options. This options are combined with AND so by using all filters i have 6 where clauses and so on.

Two questions:

  1. Is there a way to code this dynamic where query with spring data jdbc?

  2. How can i access the underlying DataSource (or maybe a JdbcTemplate) to fire this query directly?

For example:

  1. this.jdbcTemplate.query = query // the dynamic query with 6 or less where clauses;
  2. List&lt;Result&gt; results = this.jdbcTemplate.run();

Thank you!

EDIT

There is a JdbcAggregateTemplate with a &lt;T&gt; Iterable&lt;T&gt; findAll(Query query, Class&lt;T&gt; domainType); query. Is this the right place?

In contrary to other posts stated, i cannot autowire an EntityManager bean.

答案1

得分: 2

以下是翻译好的部分:

  • 你可以使用按示例查询
  • 你可以创建一个Example,从一个已填充了部分条目的实体中创建:
  1. Person person = new Person();
  2. person.setFirstname("Dave");
  3. Example<Person> example = Example.of(person);

然后可以将其与扩展了QueryByExampleExecutor的存储库一起使用:

  1. public interface QueryByExampleExecutor<T> {
  2. <S extends T> S findOne(Example<S> example);
  3. <S extends T> Iterable<S> findAll(Example<S> example);
  4. // …省略了更多功能。
  5. }

你可以微调示例的使用方式:

  1. Person person = new Person();
  2. person.setFirstname("Dave");
  3. ExampleMatcher matcher = ExampleMatcher.matching()
  4. .withIgnorePaths("lastname")
  5. .withIncludeNullValues()
  6. .withStringMatcher(StringMatcher.ENDING);
  7. Example<Person> example = Example.of(person, matcher);
  • 使用JdbcAggregateTemplate

它具有接受Query的半公共特性。它没有很好的文档说明。查看源代码以了解如何使用它。

  • 使用JdbcTemplate

你需要手动构建你的SQL。

  • 你不能注入EntityManager

它是一个JPA组件,与Spring Data JDBC无关。

英文:

You have multiple options:

You can use Query By Example.

You'd create an Example from an entity where some entries are filled:

  1. Person person = new Person();
  2. person.setFirstname(&quot;Dave&quot;);
  3. Example&lt;Person&gt; example = Example.of(person);

And then using it with your repository, which would extend QueryByExampleExecutor:

  1. public interface QueryByExampleExecutor&lt;T&gt; {
  2. &lt;S extends T&gt; S findOne(Example&lt;S&gt; example);
  3. &lt;S extends T&gt; Iterable&lt;S&gt; findAll(Example&lt;S&gt; example);
  4. // … more functionality omitted.
  5. }

and you can fine tune how the example is used:

  1. Person person = new Person();
  2. person.setFirstname(&quot;Dave&quot;);
  3. ExampleMatcher matcher = ExampleMatcher.matching()
  4. .withIgnorePaths(&quot;lastname&quot;)
  5. .withIncludeNullValues()
  6. .withStringMatcher(StringMatcher.ENDING);
  7. Example&lt;Person&gt; example = Example.of(person, matcher);

Use the JdbcAggregateTemplate

It has the semi public feature of accepting a Query.
It is not properly documented. Checkout the source code for how to use it.

Use a JdbcTemplate

You'll have to construct your SQL manually

You can NOT inject an EntityManger

It is a JPA artefact and Spring Data JDBC has nothing to do with JPA.

答案2

得分: 0

Jens的答案绝对正确。

在与同事讨论后,我得出了与他的建议相对的解决方案。

由于我有6个搜索选项,查询构建可能会有很多切换块。

简而言之,我做了这个(未编辑或缩短以显示查询的复杂性):

  1. @Query(&quot;&quot;&quot;
  2. select p.projectname, p.unit, p.cost_unit as costUnit, p.chapter, u.username, w.firstname, w.lastname, e.comment, e.value, e.entry_date as entry,
  3. w.active_from as activeFrom, w.active_to as activeTo, w.type, w.hwl, w.further, w.compensation, w.delegation, w.amount
  4. from projects p
  5. left join users u on p.users_id = u.id
  6. left join workers w on w.projects_id = p.id
  7. left join entries e on e.workers_id = w.id
  8. where trim(lower(p.projectname)) like concat(&#39;%&#39;, lower(:projectName))
  9. and trim(lower(concat(w.firstname, w.lastname))) like concat(&#39;%&#39;, lower(:workerName))
  10. and trim(lower(u.username)) like concat(&#39;%&#39;, lower(:userName))
  11. and extract(year from e.entry_date) &gt;= :year
  12. and trim(lower(p.cost_unit)) like concat(&#39;%&#39;, lower(:costUnit), &#39;%&#39;)
  13. and trim(lower(p.unit)) like concat(&#39;%&#39;, lower(:unit), &#39;%&#39;)&quot;&quot;&quot;)
  14. List&lt;SearchResultDto&gt; search(String projectName, String workerName, String userName, Integer year, String costUnit, String unit);

诀窍是对字符串查询使用%运算符。当参数为null或空字符串时,我会将其传递给查询。

因此,会返回给定列的所有条目。
%projectName会返回包含projectName的所有条目。

年份也是同样的原理。如果在用户界面中选择了年份,它将传递给查询。如果没有选择,我会使用0作为年份,以便选择所有年份。

英文:

Jens` answer is absolutely right.

After talks with collegues i ended up with an alternative to his tips.

Since i have 6 search options the query building will be likely a lot of switch blocks.

In short: I did this (not edited or shortened to sketch the complexity of the query):

  1. @Query(&quot;&quot;&quot;
  2. select p.projectname, p.unit, p.cost_unit as costUnit, p.chapter, u.username, w.firstname, w.lastname, e.comment, e.value, e.entry_date as entry,
  3. w.active_from as activeFrom, w.active_to as activeTo, w.type, w.hwl, w.further, w.compensation, w.delegation, w.amount
  4. from projects p
  5. left join users u on p.users_id = u.id
  6. left join workers w on w.projects_id = p.id
  7. left join entries e on e.workers_id = w.id
  8. where trim(lower(p.projectname)) like concat(&#39;%&#39;, lower(:projectName))
  9. and trim(lower(concat(w.firstname, w.lastname))) like concat(&#39;%&#39;, lower(:workerName))
  10. and trim(lower(u.username)) like concat(&#39;%&#39;, lower(:userName))
  11. and extract(year from e.entry_date) &gt;= :year
  12. and trim(lower(p.cost_unit)) like concat(&#39;%&#39;, lower(:costUnit), &#39;%&#39;)
  13. and trim(lower(p.unit)) like concat(&#39;%&#39;, lower(:unit), &#39;%&#39;)&quot;&quot;&quot;)
  14. List&lt;SearchResultDto&gt; search(String projectName, String workerName, String userName, Integer year, String costUnit, String unit);

The trick is to use the % operator for string queries. When the parameter is null or empty string, i'll pass it on to the query.

So % yields all entries for the given column.
Whereas %projectName yields all entries with projectName in it.

The same works on year. If a year is selected in the UI, it goes to the query, If not, i use 0 as year so all years will be selected.

huangapple
  • 本文由 发表于 2023年8月10日 21:53:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76876409.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定