参数值与预期类型不匹配 java.util.Set

Parameter value did not match expected type java.util.Set

我有以下实体:

@Entity
public class Person extends BaseEntity {
    private static final String PETS_SEPARATOR = ";";

    @Id
    @Nonnull
    private String id;

    @Column(name = "pets")
    @Convert(converter = StringSetConverter.class)
    @Nonnull
    private Set<String> pets;
}

而 StringSetConverter 基本上在 String(由 ; 分隔)和 Set 之间进行解析。

请注意,这是继承的代码,我不能轻易更改数据库结构以将宠物关系分开 table。

这会导致数据库中有一个字符串,例如:“DOG;CAT;BIRD”。例如,我想找到所有拥有“CAT”的用户。

所以我尝试了像这样的愚蠢搜索

Specification<UserEntity> petsSpecification = 
    (root, criteriaQuery, cb) -> {
        return cb.like(root.get("pets"), "%CAT%"));
    };

这并不优雅,我知道这一点,在这里我们应该考虑分隔符(如果我有另一个动物叫“PERSIAN_CAT”会怎样?)。但无论如何,这是失败的:

Caused by: java.lang.IllegalArgumentException: Parameter value [CAT] did not match expected type [java.util.Set (n/a)]

所以只要我们在 Hibernate 中工作,这似乎是正确的,属性 pets 实际上是一个 Set,而不是一个 String。 但是在查看互联网并查看文档后,我看不到使用 Criteria API 进行此查询的明确方法。我可以使用本机查询来处理 String 而不是 Set 并采用“喜欢”的方法,但我想通过代码来完成,不依赖于数据库技术。

您可以简单地对表达式执行类型转换,返回一个新的表达式对象。

Specification<AttributePerson> rawPetSpecification =
                (root, criteriaQuery, cb) -> cb.like(root
                        .get("pets").as(String.class), "%CAT%");

OR

您可以将 Set<String> 列映射到另一个 String 类型的 属性 中:

@Column(name = "pets", insertable = false, updatable = false)
private String rawPets;

这个属性为insertable = false, updatable = false的列既不可插入也不可更新,所以它的值不会被持久化,所以你得到的是存储的值。

现在您可以像这样编写查询:

Specification<AttributePerson> rawPetSpecification =
                (root, criteriaQuery, cb) -> 
                        cb.like(root.get("rawPets"), "%CAT%");