【问题标题】:Parameter value [multiVLANSupport] did not match expected type [java.util.List (n/a)]参数值 [multiVLANSupport] 与预期类型不匹配 [java.util.List (n/a)]
【发布时间】:2020-10-06 08:25:49
【问题描述】:

我创建了一个实体类,它有一列使用 JPA 的属性转换器:

  @Convert(converter = StringListConverter.class)
  private List<String> functionSpecificationLabel;

转换器类是:

@Converter
  public class StringListConverter implements AttributeConverter<List<String>, String> {

    @Override
    public String convertToDatabaseColumn(List<String> list) {
      
      return String.join(",", list); 
    }

    @Override
    public List<String> convertToEntityAttribute(String joined) {
      return new ArrayList<>(Arrays.asList(joined.split(",")));
    }

  }

表格中列的期望值是这样的

functionSpecificationLabel
multiVLANSupport,telepresence,csaid

现在我需要在functionSpecificationLabel 列中返回具有multiVLANSupport,telepresence,csaid 作为值的行。

我在存储库中的查询是:

@Query("Select pd from ProductDetailsEntity pd where pd.functionSpecificationLabel in (:labels)")
  Optional<ProductDetailsEntity> findByFunctionSpecificationLabel(@Param("labels") final List<String> labels);

现在我面临的问题是:

Parameter value [multiVLANSupport] did not match expected type [java.util.List (n/a)]

【问题讨论】:

  • 不确定是否是同一个问题,但在尝试使用具有相似关系的 jpaRepository 进行更新时出现类似错误。 hibernate上有一个相关的开放线程discourse.hibernate.org/t/…

标签: spring-boot jpa spring-data-jpa


【解决方案1】:

我不确定这是否可能,这就是我如何使用@ElementCollection 将值列表存储在实体类中您可以在此处阅读更多信息https://thorben-janssen.com/hibernate-tips-query-elementcollection/

可以在这里找到很好的讨论How to persist a property of type List<String> in JPA?。我的建议是避免基于分隔符在 db 中存储任何值。

理想情况下,在存储此类标签时,最好使用 OneToMany 关系映射它们。另请注意,在这种情况下,这将创建一个额外的表 animal_labels

回答 1

存储库

@Repository
public interface AnimalRepository extends JpaRepository<Animal, UUID> {
    List<Animal> findDistinctAnimalsByLabelsIsIn(List<String> cute);
}

实体类

@Entity
@Table(name = "animal")
public class Animal {
    @Id
    @GeneratedValue
    @Type(type = "uuid-char")
    private UUID id;

    private String name;

    @ElementCollection(targetClass = String.class)
    private List<String> labels;

    public Animal() {
    }

    public Animal(String name, List<String> labels) {
        this.name = name;
        this.labels = labels;
    }

    public UUID getId() {
        return id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getLabels() {
        return labels;
    }

    public void setLabels(List<String> labels) {
        this.labels = labels;
    }

}

测试:

@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest(classes = TestApplication.class)
class CustomConverterTest {

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private AnimalRepository animalRepository;


    @Test
    void customLabelConverter() {
        Animal puppy = new Animal("Puppy", Arrays.asList("cute", "intelligent", "spy"));
        Animal meow = new Animal("Cat", Arrays.asList("cute", "intelligent"));
        entityManager.persist(puppy);
        entityManager.persist(meow);


        List<Animal> animalWithCutelabels = animalRepository.findDistinctAnimalsByLabelsIsIn(Arrays.asList("cute"));
        List<Animal> animalWithSpylabels = animalRepository.findDistinctAnimalsByLabelsIsIn(Arrays.asList("spy"));
        List<Animal> animalWithCuteAndSpylabels = animalRepository.findDistinctAnimalsByLabelsIsIn(Arrays.asList("cute", "spy"));
        Assertions.assertEquals(2, animalWithCutelabels.size());
        Assertions.assertEquals(1, animalWithSpylabels.size());
        Assertions.assertEquals(2, animalWithCuteAndSpylabels.size());
    }
}

答案 2

如果您有任何选择,只能使用逗号分隔值,那么请在下面找到此方法的答案:

Repository(因为这是一个字符串,我们不能使用像in这样的列表)

@Repository
public interface AnimalRepository extends JpaRepository<Animal, UUID> {
    // Also note that the query goes as string and not list 
    List<Animal> findAllByLabelsContaining(String labels);
}

测试:

@Test
    void customLabelConverter() {
        Animal puppy = new Animal("Puppy", String.join(",", Arrays.asList("cute", "intelligent", "spy")));
        Animal meow = new Animal("Cat", String.join(",", Arrays.asList("cute", "intelligent")));
        entityManager.persist(puppy);
        entityManager.persist(meow);


        List<Animal> animalWithCutelabels = animalRepository.findAllByLabelsContaining(String.join(",", Arrays.asList("cute")));
        List<Animal> animalWithSpylabels = animalRepository.findAllByLabelsContaining(String.join(",", Arrays.asList("spy")));
        Assertions.assertEquals(2, animalWithCutelabels.size());
        Assertions.assertEquals(1, animalWithSpylabels.size());
    }

实体:

@Entity
@Table(name = "animal")
public class Animal {
    @Id
    @GeneratedValue
    @Type(type = "uuid-char")
    private UUID id;

    @Column
    private String name;

    @Column
    private String labels;

    public Animal() {
    }

    public Animal(String name, String labels) {
        this.name = name;
        this.labels = labels;
    }

    public UUID getId() {
        return id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getLabels() {
        if (StringUtils.isEmpty(labels)) return Collections.emptyList();
        return new ArrayList<>(Arrays.asList(labels.split(AnimalLabelsConverter.DELIMITER_COMMA)));
    }

    public void setLabels(List<String> labels) {
        if (CollectionUtils.isEmpty(labels)) {
            this.labels = "";
        } else {
            this.labels = String.join(AnimalLabelsConverter.DELIMITER_COMMA, labels);
        }
    }

    @Converter
    public static class AnimalLabelsConverter implements AttributeConverter<List<String>, String> {
        private static final String DELIMITER_COMMA = ",";

        @Override
        public String convertToDatabaseColumn(List<String> labels) {
            if (CollectionUtils.isEmpty(labels)) return "";
            return String.join(DELIMITER_COMMA, labels);
        }

        @Override
        public List<String> convertToEntityAttribute(String dbData) {
            if (StringUtils.isEmpty(dbData)) return Collections.emptyList();
            return new ArrayList<>(Arrays.asList(dbData.split(DELIMITER_COMMA)));
        }
    }
}

【讨论】:

  • 将值存储在表中没有问题,转换器对我来说可以正常工作。问题是当我尝试在表中搜索值并且我必须匹配具有逗号分隔字符串的列的值时,它不允许这样做。
  • 我已经添加了一个答案,如果可能的话,请您稍微改变一下方法。
  • 我已经查看了您的答案,因为我必须多次访问您的存储库,并且搜索参数将被一一检查。但是我只想在尝试使用本机 Query
    SELECT * FROM grp_product_details WHERE function_specification_label REGEXP 'multiVLANSupport.telepresence.csaid';
    后才访问数据库,但问题是 REGEX 只能在 REGEX 中找到具有相同序列的值,我需要找出一个正则表达式以任何顺序搜索字符串
猜你喜欢
  • 2022-11-10
  • 2020-06-22
  • 2019-09-03
  • 2019-10-22
  • 2022-06-29
  • 2019-07-23
  • 1970-01-01
  • 2018-08-17
  • 2022-01-08
相关资源
最近更新 更多