4

Hi Spring and Hibernate experts!

Can any one say if it is possible to use SQL IN-clause in custom @Query in CrudRepository while the Arraylist or set of strings is passed as parameter?

I am relatively new to Spring and do not quite figure out why I get the following Spring error:

"java.lang.IllegalArgumentException: Parameter value [d9a873ed-3f15-4af5-ab1b-9486017e5611] did not match expected type [IoTlite.model.Device (n/a)]"

In this post (JPQL IN clause: Java-Arrays (or Lists, Sets...)?) the subject is discussed pretty closely but I cannot make the suggested solution to work in my case with custom @Query.

My demo repository as part of the spring boot restful application is the following:

@Repository
public interface DeviceRepository extends JpaRepository<Device, Long> {        
    @Query("SELECT d FROM Device d WHERE d IN (:uuid)")
    List<Device> fetchUuids(@Param("uuid") Set<String> uuid);
}

And the model-class is the following:

@Entity
@SequenceGenerator(sequenceName = "device_seq", name = "device_seq_gen", allocationSize = 1)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Device implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "device_seq_gen")
    @JsonIgnore
    private Integer id;

    @Column(unique=true, length=36)
    @NotNull
    private String uuid = UUID.randomUUID().toString();

    @Column(name="name")
    private String name;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String description;

    @OneToMany(
            mappedBy="device",
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    private List<Sensor> sensors = new ArrayList<>();


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @JsonIgnore
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getDeviceUuid() {
        return uuid;
    }

    public void setDeviceUuid(String deviceUuid) {
        this.uuid = deviceUuid;
    }

    public List<Sensor> getSensors() {
        return sensors;
    }

    public void addSensor(Sensor sensor){
        sensor.setDevice(this);
        sensors.add(sensor);
    }

}

An here is the relevant part of the service calling the fetchUuids-custom-method with set-list of strings as parameter (service naturally being called by the relevant restcontroller):

@Service
public class DeviceService implements IDeviceService {

    @Autowired 
    private DeviceRepository deviceRepository;

...

    @Override
    public List<Device> listDevices(Set<String> clientIds) {
        return deviceRepository.fetchUuids(clientIds);
    }
...
}
Tomas Pinos
  • 2,812
  • 14
  • 22
M.Y.
  • 549
  • 1
  • 3
  • 23

3 Answers3

6

Quick fix

You have WHERE d IN (:uuid) in the custom query. You cannot match d, which is an alias for Device entity with :uuid parameter, which is a collection of Strings.

WHERE d.uuid IN (:uuid) would fix the query - it matches a String with Strings.

What you should do instead

It's rather misleading to name the method fetchUuids and return a list of Device instances. It's also unnecessary to write a custom query to do that. You can benefor from repository method name conventions and let Spring Data Jpa framework generate the query for you:

List<Device> findByUuidIn(Set<String> uuids);
Tomas Pinos
  • 2,812
  • 14
  • 22
  • Perfect answer for a novice like me - thank you very much for your expertise! - Can you, please yet, point me to some good tutorial which elucidates repository method name conventions and their usage with many-sided practical examples! – M.Y. Oct 30 '18 at 11:30
  • 1
    I always like Spring blog - [Getting started with Spring Data JPA](https://spring.io/blog/2011/02/10/getting-started-with-spring-data-jpa/), [Advanced Spring Data JPA - Specifications and Querydsl](https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/) or [Spring Tips: JPA](https://spring.io/blog/2018/06/06/spring-tips-jpa), if video is what you prefer. [Spring Data JPA - Reference](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/) also makes a good reading. – Tomas Pinos Oct 31 '18 at 08:51
  • Highly relevant guides, particularly the last one. Video I have not yet watched. Thanks for links! – M.Y. Oct 31 '18 at 10:22
1

You can write in this way

@Query(value = "select name from teams where name in :names", nativeQuery = true)
List<String> getNames(@Param("names") String[] names);

and call the function in service and pass an array of String as arguments.like this

String[] names = {"testing team","development team"};
List<String> teamtest = teamRepository.getNames(names);
Shubham
  • 707
  • 9
  • 7
0

Yes is possible to using collection in JPA query parameters. Your query is wrong, it should be like this:

@Query("SELECT d FROM Device d WHERE d.uuid IN :uuid")