在列表或设置为传递参数的JPA- / CrudRepository中的自定义@Query中使用SQL-IN子句?

时间:2018-10-30 09:16:55

标签: java spring hibernate spring-data-jpa jpa-2.0

您好,Spring和Hibernate专家!

有人可以说,在将Arraylist或字符串集作为参数传递时,是否可以在CrudRepository的自定义@Query中使用SQL IN子句?

我对Spring还是比较陌生,还不太清楚为什么会出现以下Spring错误:

“ java.lang.IllegalArgumentException:参数值[d9a873ed-3f15-4af5-ab1b-9486017e5611]与预期的类型[IoTlite.model.Device(n / a)]不匹配”

在这篇文章(JPQL IN clause: Java-Arrays (or Lists, Sets...)?)中,我们对该主题进行了非常详细的讨论,但是我无法针对自定义@Query提出建议的解决方案。

我的演示存储库是spring boot restful应用程序的一部分:

@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);
}

模型类如下:

@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);
    }

}

这是调用fetchUuids-custom-method的服务的相关部分,以字符串的set-list作为参数(服务自然由相关的restcontroller调用):

@Service
public class DeviceService implements IDeviceService {

    @Autowired 
    private DeviceRepository deviceRepository;

...

    @Override
    public List<Device> listDevices(Set<String> clientIds) {
        return deviceRepository.fetchUuids(clientIds);
    }
...
}

3 个答案:

答案 0 :(得分:2)

快速修复

自定义查询中有WHERE d IN (:uuid)。您无法将d(这是Device实体的别名,该实体与:uuid参数,它是字符串的集合)相匹配。

WHERE d.uuid IN (:uuid)将解决该查询-它将字符串与字符串匹配。

您应该做什么

将方法命名为fetchUuids并返回Device实例的列表是很容易引起误解的。也不必编写自定义查询来执行此操作。您可以从存储库方法名称约定中受益,并让Spring Data Jpa框架为您生成查询:

List<Device> findByUuidIn(Set<String> uuids);

答案 1 :(得分:0)

是的,可以在JPA查询参数中使用collection。 您的查询是错误的,应该是这样的:

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

答案 2 :(得分:0)

您可以用这种方式写

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

并在服务中调用该函数,然后将String数组作为参数传递。

String[] names = {"testing team","development team"};
List<String> teamtest = teamRepository.getNames(names);