0

I've used the following previously asked question to develop a nice enough solution to search across most of my columns by keyword. My issue is I have columns that are foreign keys to other entities and I'd like to include them in the search.

Neither of the following work:

SearchSpecification byBedroom = new SearchSpecification(new SearchCriteria("masterBedroom", ":", "searchVal")); Executes but returns only non-foreign entities OR

SearchSpecification byBedroom = new SearchSpecification(new SearchCriteria("masterBedroom.roomName", ":", "searchVal")); throws an exception - org.springframework.dao.InvalidDataAccessApiUsageException: Unable to locate Attribute with the the given name [masterBedroom.roomName] on this ManagedType.

What am I missing here?

ebilly
  • 33
  • 1
  • 4

1 Answers1

1

I would suggest to use QueryDSL for filter based search as it's much more readable than Spring data Specifications or Criteria API.

  1. Add dependencies

    <querydsl.version>5.0.0</querydsl.version>

<dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-core</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>${querydsl.version}</version>
            <classifier>jakarta</classifier>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-sql</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-sql-spring</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
            <classifier>jakarta</classifier>
        </dependency>

Run mvn clean install - it will generate querydsl model classes.

  1. Create a search param pojo Below example is using record
@Builder(toBuilder = true)
public record UserProfileFilterParam(String city, String country, String state, Integer pincode) {}
  1. Create a search repository interface
public interface UserProfileFilterRepository {

    List<UserProfile> fetchAll(UserProfileFilterParam filter);

    //Add methods if needed
}
  1. Create an implementation of repo in step 3
@Repository
public class UserProfileFilterRepositoryImpl extends QuerydslRepositorySupport implements UserProfileFilterRepository {

    public UserProfileFilterRepositoryImpl() {
        super(UserProfile.class);
    }

    @Override
    public List<UserProfile> fetchAll(UserProfileFilterParam filter) {
        //Classes started with 'Q' are autogenerated by QueryDSL when executed maven build command.
        QUserProfile userProfile = QUserProfile.userProfile; //root
        QAddress address = QAddress.address; //foreign keys
        JPQLQuery<UserProfile> query = from(userProfile)
                .join(address).on(userProfile.address.id.eq(address.id));

        if(filter.city() != null) {
            query = query.where(address.city.likeIgnoreCase(filter.city()));
        }

        if(filter.country() != null) {
            query = query.where(address.country.likeIgnoreCase(filter.country()));
        }

        if(filter.state() != null) {
            query = query.where(address.state.likeIgnoreCase(filter.state()));
        }

        if(filter.pincode() != null) {
            query = query.where(address.pinCode.likeIgnoreCase(Integer.toString(filter.pincode())));
        }
        return query.orderBy(userProfile.id.asc()).fetch();
    }
}

More details: https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl https://www.baeldung.com/rest-api-search-language-spring-data-querydsl

Govil Kumar
  • 130
  • 2
  • 2
  • 10
  • Thank you. This seems to be the answer but I’m required to upgrade my Spring version to use query DSL. I’m using 2.7.2 and needed 3.0 to compile and run which caused a bunch of other issues. ;) Brilliant solution though. I’ll have to look for something else until I’m ready to upgrade. Sigh. – ebilly Feb 19 '23 at 16:48
  • 1
    Check this out https://zetcode.com/springboot/querydsl/ might help you. – Govil Kumar Feb 20 '23 at 03:02