2

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<Result> results = this.jdbcTemplate.run();

Thank you!

EDIT

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

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

2 Answers 2

3

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("Dave");                          

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

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

public interface QueryByExampleExecutor<T> {

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

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

  // … more functionality omitted.
}

and you can fine tune how the example is used:

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

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

Example<Person> 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.

Sign up to request clarification or add additional context in comments.

3 Comments

Hey Jens, thank you for your suggestions. I will give it a try and post my solution here as soon as it works. By the way - Spring Data JDBC has become my first choice of ORM tool. Superb job!!!
Concerning Query By Example? I can only use a Domain Type for this type? In the examples there is the Person Domain Object. What if i need a (SearchResults)DTO built of various properties from Person joins? Let's say Person->Address; Person->Employments; Person->Contracts and so on? Is this possible?
No, that is not possible. In that case a JdbcTemplate or NamedParameterJdbcTemplate is the better choice.
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("""
            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('%', lower(:projectName))
            and trim(lower(concat(w.firstname, w.lastname))) like concat('%', lower(:workerName))
            and trim(lower(u.username)) like concat('%', lower(:userName))
            and extract(year from e.entry_date) >= :year
            and trim(lower(p.cost_unit)) like concat('%', lower(:costUnit), '%')
            and trim(lower(p.unit)) like concat('%', lower(:unit), '%')""")
List<SearchResultDto> 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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.