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

M.Y*_*.Y. 3 java spring hibernate jpa-2.0 spring-data-jpa

嗨 Spring 和 Hibernate 专家!

任何人都可以说是否可以在 CrudRepository 中的自定义 @Query 中使用 SQL IN 子句,而 Arraylist 或一组字符串作为参数传递?

我对 Spring 比较陌生,不太明白为什么会出现以下 Spring 错误:

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

在这篇文章(JPQL IN 子句: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);
}
Run Code Online (Sandbox Code Playgroud)

模型类如下:

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

}
Run Code Online (Sandbox Code Playgroud)

这里是服务的相关部分,调用 fetchUuids-custom-method 并使用 set-list of strings 作为参数(服务自然会被相关的 restcontroller 调用):

@Service
public class DeviceService implements IDeviceService {

    @Autowired 
    private DeviceRepository deviceRepository;

...

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

Tom*_*nos 5

快速解决

WHERE d IN (:uuid)在自定义查询中。您不能匹配d,它是Device带有:uuid参数的实体的别名,它是字符串的集合。

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

你应该怎么做

命名方法fetchUuids并返回Device实例列表是相当具有误导性的。也没有必要编写自定义查询来执行此操作。您可以从存储库方法名称约定中受益,并让 Spring Data Jpa 框架为您生成查询:

List<Device> findByUuidIn(Set<String> uuids);
Run Code Online (Sandbox Code Playgroud)