Spring JPA Repository - jsonObject 上的运算符 SIMPLE_PROPERTY 需要标量参数

Posted

技术标签:

【中文标题】Spring JPA Repository - jsonObject 上的运算符 SIMPLE_PROPERTY 需要标量参数【英文标题】:Spring JPA Repository - Operator SIMPLE_PROPERTY on jsonObject requires a scalar argument 【发布时间】:2020-06-09 08:08:53 【问题描述】:

我正在使用 JPA 查询更新一些 Spring Boot 应用程序。除了一种特定类型的查询 (findByJsonNode) 外,一切正常。这在早期版本中运行良好,但升级后无法创建 bean。

在 Spring Boot 2.1.4.RELEASE 和 Spring Cloud 版本 Greenwich.SR1 之前它运行良好,但是当我升级到 Spring Boot 2.2.4.RELEASE 和 Spring Cloud 版本 Hoxton.RELEASE 时,Spring 无法创建我的存储库 bean。

Caused by: java.lang.IllegalStateException: Operator SIMPLE_PROPERTY on searchDto requires a scalar argument, found class com.fasterxml.jackson.databind.JsonNode in method public abstract se.company.search.Search se.company.search.SearchRepository.findFirstBySearchDto(com.fasterxml.jackson.databind.JsonNode).
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.throwExceptionOnArgumentMismatch(PartTreeJpaQuery.java:171)
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.validate(PartTreeJpaQuery.java:147)
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:90)
    ... 73 common frames omitted.
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.throwExceptionOnArgumentMismatch(PartTreeJpaQuery.java:171) ~[spring-data-jpa-2.2.4.RELEASE.jar:2.2.4.RELEASE]
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.validate(PartTreeJpaQuery.java:147) ~[spring-data-jpa-2.2.4.RELEASE.jar:2.2.4.RELEASE]
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:90) ~[spring-data-jpa-2.2.4.RELEASE.jar:2.2.4.RELEASE]
    ... 74 common frames omitted

存储库类如下所示

@Repository
public interface SearchRepository extends PagingAndSortingRepository<Search, String> 

    Search findFirstBySearchDto(JsonNode searchDto);


实体

/**
 * Entity for saving as search
 *
 * Users can save searches and every search will be stored in history for reference
 */
@Slf4j
@Data
@Entity(name = "search")
@Table(name = "tt_searches", indexes = 
        @Index(columnList = "searchDto", name = "searchdto_hidx")
)
@TypeDef(
        name = "json-node",
        typeClass = JsonNodeStringType.class
)
@EqualsAndHashCode(exclude =  "id", "savedSearches", "searchHistory" )
public class Search 

    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().findAndRegisterModules();

    public Search() 
    

    public Search(SearchDto searchDto, List<SavedSearch> savedSearches, List<SearchHistory> searchHistory) 
        this.searchDto = OBJECT_MAPPER.valueToTree(searchDto);
        this.savedSearches = savedSearches;
        this.searchHistory = searchHistory;
    

    public Search(JsonNode searchDto, List<SavedSearch> savedSearches, List<SearchHistory> searchHistory) 
        this.searchDto = searchDto;
        this.savedSearches = savedSearches;
        this.searchHistory = searchHistory;
    

    @Id
    @Column(columnDefinition = "CHAR(36)")
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    @Type(type = "json-node")
    @Column(columnDefinition = "VARCHAR(2000)", unique = true)
    private JsonNode searchDto;

    @OneToMany(mappedBy = "search", fetch = FetchType.LAZY)
    @OrderBy("name DESC")
    @JsonIgnore
    private List<SavedSearch> savedSearches;

    @OneToMany(mappedBy = "search", fetch = FetchType.LAZY)
    @OrderBy("timestamp DESC")
    @JsonIgnore
    private List<SearchHistory> searchHistory;

    public SearchDto getSearchDto() 
        try 
            return OBJECT_MAPPER.treeToValue(searchDto, SearchDto.class);
         catch (JsonProcessingException e) 
            log.error("Could not convert JsonNode to SearchDto when retrieving data from entity: ", this.id);
            return null;
        
    

    public void setSearchDto(SearchDto searchDto) 
        this.searchDto = OBJECT_MAPPER.valueToTree(searchDto);
    

【问题讨论】:

我现在在尝试更新时在另一个应用程序中遇到了同样的错误,但现在在 java.util.Set 作为 JPA 查询的帮助下找到时,就像这样 findAllByTags(java.util.Set) 不确定,但您尝试过使用findByTagsIn 吗?您可能已经看到了这一点。 jira.spring.io/browse/DATAJPA-1182 添加了一个验证来检查收集的方法签名。还有一个关于自定义集合转换器问题的错误报告。 jira.spring.io/browse/DATAJPA-1682 只是为了澄清,问题表明您正在将集合或多个值传递给需要单个值的参数。这可能有助于调试,谢谢 【参考方案1】:

我遇到了同样的问题。我通过在方法的末尾添加“In”来更改方法的名称来解决它。

对于你的例子,它会是

findAllByTagsIn(java.util.Set)

在此处查看“方法名称中支持的关键字”表:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation

【讨论】:

这很好用。如此简单的愚蠢解决方案。从来没有想过它,因为我没有使用集合而是对象JsonNode。谢谢!【参考方案2】:

如果您正在使用存储库并尝试基于 Set 类型的参数获取列表,则在编写查询时应该小心!就我而言:

findAllBySchoolId(Set<Long> schoolIds) // wrong
findAllBySchoolIdIn(Set<Long> schoolIds) // correct

感谢用户:8569305(smythie)!

【讨论】:

【参考方案3】:

当您使用列值列表作为谓词搜索实体时,您必须在列名末尾使用“In”子句。你可以使用无误

List<Entity> findAllByEntityColumnIn(Iterable<Long> EntityColumns);

注意:它在我的项目中 100% 测试过。

【讨论】:

以上是关于Spring JPA Repository - jsonObject 上的运算符 SIMPLE_PROPERTY 需要标量参数的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA 提供的各种Repository接口作用

spring boot: spring-data-jpa (Repository/CrudRepository) 数据库操作, @Entity实体类持久化

使用 RepositoryItemReader 和 Repository Item writer 的 spring 数据 JPA 的 spring 批处理

Spring Data JPA Repository:如何有条件地获取子实体

删除分离实体spring jpa Repository接口

Spring JPA Repository 生成不正确的 SQL