darrachequesne / spring-data-jpa-datatables

Spring Data JPA extension to work with the great jQuery plugin DataTables (https://datatables.net/)
Apache License 2.0
447 stars 173 forks source link

DataTablesSpecification does not handle collection members #3

Closed tomcgn closed 8 years ago

tomcgn commented 8 years ago

The current implementation works fine if the Specification is applied to simple members of the domain classes. In metamodel vocabulary: If a search term should be matched against an attribute that is if type SetAttribute instead of SingularAttribute, the repository returns no matches.

A simple example might be domain classes Meeting and Tag, where Meeting has @ManyToMany Set<Tag> tags . If a user enters a search term 'foo' in the datatable, matches should take into account all meetings, where either meeting.description or one of meeting.tags[] has the value 'foo'.

The method toPredicate in DataTablesSpecification<T> might need to be adapted in way that it is capable to handle the occurence of the filter value in one of multiple tags assigned to the meeting.

Can you verify that this is not yet possible? What would be the right place to make the distinction of whether the attribute that is to be filtered is flat or a collection. And what are the appropriate predicates or cirteriaBuilder calls to make? Quite a bit, for sure. The documentation on Advanced Spring Data JPA does not contain an example of this use case. If from your point of view it does not seem feasible to implement, it would be helpful to know to :grinning: .

darrachequesne commented 8 years ago

Hi! That is a great question. The basic Specification is indeed limited to class attributes or @ManyToOne relationships. The SQL counterpart are:

That is the very basic usage. For more complex needs, my opinion is that Datatables (and thus this implementation) has absolutly no clue about what the user wants to do. So it lets him make whatever he wants (handling @ManyToMany relationships, using 'BETWEEN' clause...) through the following method: public DataTablesOutput<T> findAll(DataTablesInput input, Specification<T> additionalSpecification).

With this, the user is able to either pass directly the input object mapped from the request (the basic usage) or process this input to create an additionalSpecification according to his needs. Please see this example: https://github.com/darrachequesne/demo-spring-datatables/blob/master/src/main/java/demo/controller/UserRestController.java#L46

In that example, the "classic" filter value is cleared, and a custom Specification is built from the latter. I think it should cover most use-cases, but please tell me if I'm wrong.

tomcgn commented 8 years ago

Hi Damien, Thanks for your insights. Your design condiserations are straightforward and fully serve the purpose. As far as I can see, the Specification passed as parameter to findAll can not be written in a way that it is capable to handle collection attributes. Finally, I ended up rewriting your DataTablesRepositoryImpl and wire the required specification in its public DataTablesOutput<T> findAll(DataTablesInput input, Specification<T> additionalSpecification) and thus gain control over related SetAttributes via Subquerys . The datatables now work fine and serverside processing with spring-data-jpa-datatables reduces the time for pages to get displayed a lot. Again, thanks for sharing! Tom