gpt4 book ai didi

Spring 数据 : Query By Example and Converter

转载 作者:行者123 更新时间:2023-12-04 13:37:33 28 4
gpt4 key购买 nike

我有一个实体:

import javax.persistence.Convert;

@Entity(name = "my_entity")
public class MyEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

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

// next fields omitted...

}
emails 使用的转换器实体中的字段(典型实现如 LocalDateTimeConverter ):
import javax.persistence.Converter;

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

@Override
public String convertToDatabaseColumn(List<String> stringList) {
if (CollectionUtils.isNotEmpty(stringList)) {
return String.join(SPLIT_CHAR, stringList);
} else {
return null;
}
}

@Override
public List<String> convertToEntityAttribute(String string) {
if (StringUtils.isNotBlank(string)) {
return Arrays.asList(string.split(SPLIT_CHAR));
} else {
return Collections.emptyList();
}
}

}

(我将以分号分隔的电子邮件存储在一列中。 StringListConverter 进行该转换。)

和 Spring 数据存储库:
import org.springframework.data.domain.Example;

public interface MyRepository extends JpaRepository<MyEntity, Long> {

default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
Example<MyEntity> example = Example.of(myEntity);
return findAll(example);
}

}

我使用 Spring Data 中的 Query by Example 机制。当我有没有 @Convert 的字段时(如 String name )它有效。但是当我有 @Convert 的字段时( AttributeConverter ) 喜欢 List<String> emails它导致 InvalidDataAccessApiUsageException .
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [abc@company.com] did not match expected type [java.util.List (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [abc@company.com] did not match expected type [java.util.List (n/a)]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.2.1.RELEASE.jar:5.2.1.RELEASE]
...
Caused by: java.lang.IllegalArgumentException: Parameter value [abc@company.com] did not match expected type [java.util.List (n/a)]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.query.internal.QueryParameterBindingImpl.validate(QueryParameterBindingImpl.java:90) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
... 146 common frames omitted

(消息很奇怪,因为我尝试使用该列表进行搜索: ["abc@company.com", "def@company.com"] ,但消息中只有一封电子邮件)

我试过实现 transformExampleMatcher :
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;

public interface MyRepository extends JpaRepository<MyEntity, Long> {

default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("emails",
match -> match.transform(emailsOptional -> {
if (emailsOptional.isPresent()) {
List<String> emails = (List<String>) emailsOptional.get();
return Optional.ofNullable(new StringListConverter().convertToDatabaseColumn(emails));
}
return emailsOptional;
}));
Example<MyEntity> example = Example.of(myEntity, matcher);
return findAll(example);
}

}

但是是原因 InvalidDataAccessApiUsageException也是,但与之前的消息不同(我设置了两封电子邮件):
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [abc@company.com;def@company.com] did not match expected type [java.util.List (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [abc@company.com;def@company.com] did not match expected type [java.util.List (n/a)]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
Caused by: java.lang.IllegalArgumentException: Parameter value [abc@company.com;def@company.com] did not match expected type [java.util.List (n/a)]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
... 146 common frames omitted

最佳答案

似乎出于某种原因,Hibernate 试图将电子邮件数组拆分为多个条件,就像在 IN 中一样。使用 expandListValuedParameters 在 SQL 中查询方法。
注意 - 使用您的解决方案进行查询,如 findAllByEmailsIn(List<String> emailsList)也行不通。
方法expandListValuedParameters自 Hibernate 5.2 起已弃用,因此它可能包含一些问题,并且肯定会在 Hibernate 6.0 中以不同的方式实现。
我还没有找到解决您的问题的方法,但有一些解决方法:

  • 包裹您的 List<String> emails在另一个类(class)

  • 包装类:
    public class EmailList {

    private List<String> emails;

    // getters, setters, constructors ommited

    }
    更新模型类:
    import javax.persistence.Convert;

    @Entity(name = "my_entity")
    public class MyEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Convert(converter = StringEmailListConverter.class)
    private EmailList emailList;

    // next fields omitted...
    }
    更新的转换器类:
    import javax.persistence.Converter;

    @Converter
    public class StringEmailListConverter implements AttributeConverter<EmailList, String> {
    private static final String SPLIT_CHAR = ";";

    @Override
    public String convertToDatabaseColumn(EmailList emailList) {
    if (emailList != null && CollectionUtils.isNotEmpty(emailList.getEmails())) {
    return String.join(SPLIT_CHAR, emailList.getEmails());
    } else {
    return null;
    }
    }

    @Override
    public EmailList convertToEntityAttribute(String string) {
    if (StringUtils.isNotBlank(string)) {
    return new EmailList(Arrays.asList(string.split(SPLIT_CHAR)));
    } else {
    return new EmailList(Collections.emptyList());
    }
    }

    }
    并且 Spring Data 存储库可以很好地使用此代码 - 无需使用 transform :
    import org.springframework.data.domain.Example;

    public interface MyRepository extends JpaRepository<MyEntity, Long> {

    default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
    Example<MyEntity> example = Example.of(myEntity);
    return findAll(example);
    }

    }
  • 使用 String[] emails而不是 List<String> emails您需要分别更改 MyEntity 和 Converter 才能使用 String[] .当然使用 String[]有时不是一种选择,因为您特别需要一个列表。
  • 关于 Spring 数据 : Query By Example and Converter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60873941/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com