Spring Data JDBC 动态的 where 子句

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

Spring Data JDBC dynamic where clauses

问题

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

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

例如:

this.jdbcTemplate.query = query // 具有6个或更少的`WHERE`子句的动态查询;
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:

this.jdbcTemplate.query = query // the dynamic query with 6 or less where clauses;
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,从一个已填充了部分条目的实体中创建:
Person person = new Person();                         
person.setFirstname("Dave");                          

Example<Person> example = Example.of(person);   

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

public interface QueryByExampleExecutor<T> {

  <S extends T> S findOne(Example<S> example);

  <S extends T> Iterable<S> findAll(Example<S> example);

  // …省略了更多功能。
}

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

Person person = new Person();                          
person.setFirstname("Dave");                           

ExampleMatcher matcher = ExampleMatcher.matching()     
  .withIgnorePaths("lastname")                         
  .withIncludeNullValues()                             
  .withStringMatcher(StringMatcher.ENDING);            

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:

Person person = new Person();                         
person.setFirstname(&quot;Dave&quot;);                          

Example&lt;Person&gt; example = Example.of(person);   

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

public interface QueryByExampleExecutor&lt;T&gt; {

  &lt;S extends T&gt; S findOne(Example&lt;S&gt; example);

  &lt;S extends T&gt; Iterable&lt;S&gt; findAll(Example&lt;S&gt; example);

  // … more functionality omitted.
}

and you can fine tune how the example is used:

Person person = new Person();                          
person.setFirstname(&quot;Dave&quot;);                           

ExampleMatcher matcher = ExampleMatcher.matching()     
  .withIgnorePaths(&quot;lastname&quot;)                         
  .withIncludeNullValues()                             
  .withStringMatcher(StringMatcher.ENDING);            

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个搜索选项,查询构建可能会有很多切换块。

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

@Query(&quot;&quot;&quot;
            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,
            w.active_from as activeFrom, w.active_to as activeTo, w.type, w.hwl, w.further, w.compensation, w.delegation, w.amount
            from projects p
            left join users u on p.users_id = u.id
            left join workers w on w.projects_id = p.id
            left join entries e on e.workers_id = w.id
            where trim(lower(p.projectname)) like concat(&#39;%&#39;, lower(:projectName))
            and trim(lower(concat(w.firstname, w.lastname))) like concat(&#39;%&#39;, lower(:workerName))
            and trim(lower(u.username)) like concat(&#39;%&#39;, lower(:userName))
            and extract(year from e.entry_date) &gt;= :year
            and trim(lower(p.cost_unit)) like concat(&#39;%&#39;, lower(:costUnit), &#39;%&#39;)
            and trim(lower(p.unit)) like concat(&#39;%&#39;, lower(:unit), &#39;%&#39;)&quot;&quot;&quot;)
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):

@Query(&quot;&quot;&quot;
            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,
            w.active_from as activeFrom, w.active_to as activeTo, w.type, w.hwl, w.further, w.compensation, w.delegation, w.amount
            from projects p
            left join users u on p.users_id = u.id
            left join workers w on w.projects_id = p.id
            left join entries e on e.workers_id = w.id
            where trim(lower(p.projectname)) like concat(&#39;%&#39;, lower(:projectName))
            and trim(lower(concat(w.firstname, w.lastname))) like concat(&#39;%&#39;, lower(:workerName))
            and trim(lower(u.username)) like concat(&#39;%&#39;, lower(:userName))
            and extract(year from e.entry_date) &gt;= :year
            and trim(lower(p.cost_unit)) like concat(&#39;%&#39;, lower(:costUnit), &#39;%&#39;)
            and trim(lower(p.unit)) like concat(&#39;%&#39;, lower(:unit), &#39;%&#39;)&quot;&quot;&quot;)
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:

确定