I'm trying to create a spring boot 2 web application which will fetch data from the db based on the filtering criteria passed to it, but will only fetch certain columns.
Here is my employee class:
@Entity
@Table("table=emplooyee")
class Employee{
@column("name="fname")
String fname;
@column("name="lname")
String lname;
@column("name="phoneNo")
String phoneNo;
@column("name="address")
String address;
}
There are 25 more such fields in my entity and in the db.
From the front-end the user should be able to choose a filtering criteria such as: fname, lname, phoneNo, address etc. He may specify any combination like fname and phoneNo, or lname and address or may not specify anything in which I have to do a select *. In a way, I want multiple filtering criteria. I expect these filters to come as request parameters from the front end.
My repository is:
public interface EmployeeRepository extends JpaRepository<Employee,Long>, JpaSpecificationExecutor<Employee>{
}
So far, I've looked into specifications which is pretty cool.
So I created a specification,
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
public class EmployeeSpecs {
public static Specification<Employee> hasFname(String fname){
return new Specification<Employee>() {
@Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.equal(root.get("fname"),fname);
}
};
}
public static Specification<Employee> hasLname(String lname){
return new Specification<Employee>() {
@Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.equal(root.get("lname"), lname);
}
};
}
public static Specification<Employee> hasAddress(String address){
return new Specification<Employee>() {
@Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.equal(root.get("address"), address);
}
};
}
public static Specification<Employee> hasPhone(String phone){
return new Specification<Employee>() {
@Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.equal(root.get("phone"), phone);
}
};
}
}
Now, from my service, I plan to do:
this.employeeRepository.findAll(EmployeeSpecs.hasFName(requestParameterFname).and(EmployeeSpecs.hasLName(requestParameterLname))).forEach(e->list.add(e));
However, this would fetch all the 25 columns in my db. My front end application has 6 pages, each requiring different columns to be displayed but a combination of these specifications as where clauses.
I tried looking into the concept of projection, but figured out that currently SpringBoot does not support Specification with Projection.
Is there a way to get only selected columns and have multiple filtering criteria? Any thoughts on being able to dynamically append the passed request parameters to my query and fetching only relevant fields?
Should I create separate entities so that I get only those fields from my repository and then a new specification for each of those each time? Won't this create too many unnecessary entities and specification files?
The other way I can think of is that, I'll have to manually extract those columns. This would sound stupid as I already know that I need to do a 'select column1, column2, column3 from db where condition1 = true and condition2= true'
but I'm still doing a select *
.
Can anyone please guide on what's the best approach to take in this case? What would look the most clean way of achieving this? Should I be writing a query manually, like a native query?
In a nutshell, I want the following:
- Multiple filtering criteria - any combination possible, ie. multiple conditions to be passed to the 'where' clause of my sql select statement.
- Only selected columns, not all - but different use cases require different columns.