6

I work with Spring Data and Neo4j in my current project and have the following situation:

@RestController
@RequestMapping(value = SearchResource.URI)
public class PersonResource {

public static final String URI = "/person";

@Autowired
PersonRepository personRepository;

@GetMapping
public Collection<Person> findPersons(
    @RequestParam(value = "name", required = false) String name,
    @RequestParam(value = "birthDate", required = false) Long birthDate,
    @RequestParam(value = "town", required = false) Spring town) {

    Collection<Person> persons;

    if (name != null && birthDate == null && town == null) {
        persons = personRepository.findPersonByName(name);
    } else if (name != null && birthDate != null && town == null {
        persons = personRepository.findPersonByNameAndBirthDate(name, birthDate);
    } else if (name != null && birthDate != null && town != null {
        persons = personRepository.findPersonByNameAndBirthDateAndTown(name, birthDate, town);
    } else if (name == null && birthDate != null && town == null {
        persons = findPersonByBirthDate(birthDate);
    } else if
        ...
    }
    return persons;
}
}

You probably already can see my problem: the chain of if-else-blocks. Each time I add a new filter for searching for persons, I have to add new optional parameter, double all the if-else-blocks and add new find-Methods to my PersonRepository. All the find-Methods are annotated with Spring @Query annotation and get a custom cypher query to get the data.

Is it possible to implement this functionality in a more elegant way? Does Spring Data offer any support in such situation?

Ira Re
  • 730
  • 3
  • 9
  • 25
  • 1
    Define a custom method for your repository (https://docs.spring.io/spring-data/neo4j/docs/4.2.6.RELEASE/reference/html/#repositories.single-repository-behaviour). In the method implementation, generate a query dynamically based on the search criteria, and execute it. – JB Nizet Aug 16 '17 at 15:12
  • You can try to use this approach https://stackoverflow.com/a/44705452 – Cepr0 Aug 16 '17 at 16:38
  • I have posted an answer here : https://stackoverflow.com/a/69362813/7189597 this solution looks more simple and efficient than the others to me which I found on stackoverflow or web. check it out!!!you are going to love it ;) – Sobhan Sep 28 '21 at 13:46

1 Answers1

1

I solved this problem using QueryDSL with Spring Data. There is a good tutorial on baeldung.com. With QueryDSL your spring data query is simply personRepository.findAll(predicate);.

You can use an object to represent the multiple request parameters and declare their type to be Optional<String> name; etc.

Then you can build the predicate (assuming you setup you stuff as in the linked tutorial):

Predicate predicate = new MyPredicateBuilder().with("name", ":", name.orElse(""))
.with("birthDate", ":", birthDate.orElse(""))
.with("town", ":", town.orElse(""))
.build();

I personally modified it so it didn't use the ":" as they are redundant for my usage.

AllanT
  • 923
  • 11
  • 23
  • 2
    Hello @AllanT! That seemed like a perfect solution to me. Unfortunately, Spring Data Neo4J seem to have deprecated the support for QueryDslPredicateExecutor in the current version – Ira Re Aug 17 '17 at 09:13