Spring boot search a word in all columns - spring-boot

I have a table User. A User entity has firstName, LastName, middleName. I want to get all rows that contain a word loe (LIKE %loe%) in one of these columns. I believe it narrow downs to :
Page<User> findBy<columnName>Or<ColumnName>Or(...)Contains(...)...
That should work, but what if I want to match word loe to all columns (fe. 9)? is that a proper way ? or maybe I should create a #Query for that reason ?

You could use #Query and meet your requirement. But you may want to consider using Spring Data JPA with Specifications and might be a better fit as this will reduce number of query methods in you repo and allows for reusable Predicates.
You just need to implement Specification interface and implement the method toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb) to construct and return the Predicate that satisfies your criteria. Make the repo extend JpaSpecificationExecutor. The good thing is these Predicates are reusable and you can compose them further as you want.
You can go through Advanced Spring Data JPA - Specifications and Querydsl to get an overview.
To simplify the code further, to avoid coding Specification, you may want to check Spring data JPA QueryDsl as well.

Related

Spring JPA Derived query method groupBy

Hi I was building an app and was wondering on how I can convert this query into a derived query method without using the annotation #Query:
SELECT address, COUNT(*) address FROM `employee` GROUP BY address ORDER BY address DESC LIMIT 5
I have tried it here is how I did it
List<Employee> countByAddressGroupByAddressByOrderByAddressDescLimit5();
This throws the following error
Invalid derived query! No property groupByAddressBy found for type String! Traversed path: Employee.address.
I was wondering if what am I doing wrong here thank you in advance.
I don't think query derivation supports group by.
You can't.
Derived queries don't support GROUP BY.
Derived queries are intended only for simple queries, where the mapping between a normal method name that you might choose independently from Spring Data and the query needed for implementation is obvious.
For more complex cases like the one you describe other mechanisms are available, like annotated or named queries. Nobody wants to use a method name like countByAddressGroupByAddressByOrderByAddressDescLimit5 anyway.
As others said, derived queries do not support this. There might be other reasons besides simply not being a 'practical' solution.
AFAIK derived query methods are restricted to retrieving instances just for the entity type managed by the repository (you can retrieve MyEntity, Optional<MyEntity>, Collection<MyEntity>, etcetera) or projections that match the fields/columns used for the managed entity.
When you use 'Group By', you break with this resultset structure, you usually have to explicitly indicate which columns you want to retrieve or which operations you want to perform on the grouped columns (which would be impossible using just a method name).
TL;DR
You can't easily indicate the columns you want to include in a 'Grouped By' query result, so no, I don't think there is a way to use this technique with 'Group By'.

Querying multiple tables using jpa repository

Suppose if I have 3 entities - User, Skills, Department
and I have repositories corresponding to all of them - UserRepository, SkillRepository, DepartmentRepository.
I understand that the relation mapping between entities i.e. one-one many-many should be specified in the respective entity classes. The question is I want to use all of the 3 entities in a query. How would I do it? A single repository is associated with only one entity right? So, how/where would I write it?
As there are many different ways to specify queries with Spring Data JPA there are various answers to this.
Maybe you don't have to. If entity A references B and you just want to get the Bs with your A you simply use your ARepository to load As and use object navigation to get your Bs. You might read up on eager and lazy loading for more information about how to control this.
If you want referenced entities in the where condition you can use property paths in your query method names: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-property-expressions
If you are using #Query annotations you can do (almost) whatever you want with JPQL. Among others, you may as well navigate properties to use them in where clauses.
In general, you'd put that query in the matching repository based on the primary entity returned.

Spring JPA custom query with combination of parameters in WHERE condition?

How to write JPA query in Spring Data that uses at least one of three parameters?
I have these three parameters:
Id (PK)
Name
Surname
Client must supply at least one of these three parameters and I want to find user by these not-empty parameters.
Is it possible to create such custom query to my repository or do I have to create custom queries for all possible combination of WHERE conditions?
You can have your repository extend org.springframework.data.querydsl.QueryDslPredicateExecutor and use the inherited findAll(Predicate predicate) method to query using any combination of parameters.
You would not then have to write any query methods:
http://docs.spring.io/spring-data/jpa/docs/1.10.5.RELEASE/reference/html/#core.extensions.querydsl
You can also have the Predicate automatically bound in a Spring MVC Controller as detailed here:
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#querydsl-web-support
and here:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web.type-safe
So your controller can then automatically handle a search with 1,2 or all 3 parameters passed as request parameters without your having to write any code at all.
This is where you need the ability to create dynamic queries at runtime.
In your application code, you should have logic to build the predicate based on whether each of the above properties from the input DTO is empty or not.
One way to do it is to use QueryDSL.
To use QueryDSL, you should include the relevant dependency in your pom/gradle file and then your repository should extend the QueryDslPredicateExecutor interface. This will give you two additional generic finder methods.
T findAll(Predicate) or
Page<T> findAll(Predicate, Pageable)
One thing to keep in mind is that the above two methods are appropriate where this is no need to do a join
Your requirement here seems to be a single table query, so either one of the finder methods should suffice.
If you do need to do a join with other tables and need fine grained control over how the JOIN happens (INNER JOIN vs LEFT OUTER JOIN vs CROSS JOIN) etc, then you should consider creating a Custom repository that your repository can extend.
And then provide your own customImpl that you can now access from the repository.
thanks a lot for the reply ... as i read Spring is not easy flexible as other framework... for i.e i tried some node js api framework and it is easier and more flexible .. what do you think about this ?

how to do AND and multiple OR parameters method in spring data JPA

I am trying to formulate a method name for this query :
#Query("from Employees where department = ?1 and (fullTime = true or contractor = true or subContractor = true)")
I thought this method will do the trick, but it does an and on dept and full time
public List<Employees> findByDepartmentAndfullTimeTrueOrContractorTrueOrSubContractorTrue(String dept);
This is a related question : Spring JPA Data "OR" query but was asked in 2012. Is there a way to achieve this without having to use #Query ?
This is currently not supported and probably never will be for a very simple reason:
Derived queries are considered a means to define very simple queries. I admit this is blurry but if you get to findByDepartmentAndfullTimeTrueOrContractorTrueOrSubContractorTrue it's time to rethink whether that's actually what you want to expose to clients. It's awkward to write, awkward to read and probably actually more than a collection of predicates but conveying a higher-level meaning and thus should be named in amore descriptive way.
The solution - as you already discovered - is to use #Query or Querydsl predicates.

How to obtain a generic search/find method with spring data?

All I need is to provide all my repositories with a generic search/find method.
Something like this:
public interface BaseRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID> {
Iterable<T> search(SearchParameters sp);
}
where the SearchParameters object represents a set of values for each property, and probably a condition to apply on them.
Jpa Criteria is probably the way to go, but I'm really having a hard time finding something that fits my needs.
I used one approach which goes in the same direction but i would rather say its a dynamic approach instead of generic. Its now working pretty well and we are able to generate all desired filters automatically by just giving the search entity. I also thought the criteria api is the way to go but after a while it just got too messy with all the side effects and i turned around creating the query string with parameters myself.
I created an entityscanner which takes all domain entities and generates filterdefinition objects for each desired filter. This scanner takes an entity and follows properties up to a certain level (to keep the amount of filters at bay). I cannot give you the code here since that belongs to a customer but the approach i can provide.
What i needed in the filterdefinition is this: entitytype, propertypath, propertytype, valuesexpression in case we render options (think masterdata), joins needed (to avoid joining several times the same tables), open/closed bracket. This is the definition of a filter.
Then you need a value object holding the current configuration of a user: Inputvalue, operator (>=), brackets, filter link (and/or) .
With this we can render a completly dynamic filter engine with some small limitations. I.e i did not implement parent searches of the same entity yet.
You might start simple an generate a sub query for each filter. Like: where id in (select ....) and/or id in (select ...) This works ok if the amount of entities is not too high but you will feel the performance penalty of several subqueries if the amount of rows in the domain entity table is high.
Then you dive in and find a way to separate the joins needed for a property path and in the querycreator you fiddle out the way of joining entities only again if neccessary.
As said. Start simple. Take first level properties of simple types like string and create your query engine. Enhance it by following specific entity joins and after you can go crazy and introduce expressions fetching options for a select rendering or use the conversion service for input parameters and so on.

Resources