【问题标题】:JPA and JSON operator native queryJPA 和 JSON 运算符本机查询
【发布时间】:2017-08-11 14:12:12
【问题描述】:

我正在尝试让这个查询在 JPA 中工作:

SELECT * FROM contrat WHERE contrat_json @> '{"nom" :"hever"}';

它与 postgresql 完美配合,但是当我将它与 JPA 集成时,我收到以下错误:

具有该位置 [1] 的参数不存在

我的代码:

 @Transactional
 @Query(nativeQuery = true,value = "select p from Contrat p where contrat_json @> '{\"nom\":\":nom\"}'")
    public List<Contrat> findByNomRestrict(@Param("nom") String nom);

我认为它无法识别 @&gt; 尽管原生查询,你有什么想法吗?

【问题讨论】:

  • 您使用的是哪个 jpa 版本?
  • 如果您在 spring 存储库方法中声明了 @Param 参数,您也应该在查询本身中提及它,例如 contrat_json @&gt; jsonb_build_object('nom', :nom) -- :nom 在字符串文字中仍然意味着字符::nom,不是绑定参数。
  • 我使用 spring starter jpa 1.5.1。 @pozs 我使用了你的方法,但我遇到了这个错误:“函数 jsonb_build_object(unknown, character varying) 不存在索引:没有函数匹配给定的名称和参数类型。你可能需要添加显式类型转换。”
  • @GuillaumeHochart 该函数存在于 PostgreSQL 9.5+ -- 对于 9.4,您可以使用 CAST(json_build_object(...) AS jsonb) -- 对于 9.3-,无论如何都没有 @&gt; 运算符 :)
  • @GuillaumeHochart 否,9.4 的函数是 json_build_object没有 B)。阅读我的答案。请。

标签: java json postgresql jpa hibernate-native-query


【解决方案1】:

在文字中无法理解参数持有者:'...:nom...' 将包含字符 :nom,而不是 nom 的绑定值。

对于 PostgreSQL 9.5(及更高版本),使用:

SELECT * FROM contrat WHERE contrat_json @> jsonb_build_object('nom', :nom)

对于 9.4:

SELECT * FROM contrat WHERE contrat_json @> CAST(json_build_object('nom', :nom) AS jsonb)

对于 9.3(及更早版本),没有 JSON 包含运算符(jsonb 类型也没有)。

http://rextester.com/AUHP11519

【讨论】:

    【解决方案2】:

    我的本​​机查询也有类似的问题。 jsonb字段名叫做data,很简单

    { 
       "name" : "genderList", 
       "displayName" : "gender list" 
    }
    

    我想用 JpaRepository 按名称查找,这是我的存储库

    @Repository
    public interface LookupListRepository extends JpaRepository<LookupList, UUID>
    {
        @Query(value = "SELECT * FROM lookup_list WHERE data->>'name' = :name", 
                nativeQuery = true)
        List<LookupList> findByName(@Param("name") String name);
    }
    

    您需要 nativeQuery = true。 使用 nativeQuery = true,这同样有效。

    SELECT * FROM lookup_list WHERE jsonb_extract_path_text(data, 'name') = :name
    

    我看到了您的 @Transactional 注释,我假设您在应用程序服务方法之上具有本机查询。您可以尝试移动存储库中的所有本机查询并使用 JpaRepository,并在您的应用程序服务中使用存储库方法吗? 以下是我的应用程序服务如何使用存储库。

    public class LookupListServiceImpl implements LookupListService
    {
        @Autowired
        LookupListRepository lookupListRepository;
    
        @Override
        @Transactional
        public void changeLookupList(LookupListDto lookupListDto)
        {
            List<LookupList> lookupLists = lookupListRepository.findByName(lookupListDto.getName());
            ...
        }
    
    }
    

    JPA 存储库参考 http://docs.spring.io/spring-data/jpa/docs/1.3.0.RELEASE/reference/html/jpa.repositories.html

    【讨论】:

      【解决方案3】:

      使用 PostgreSQL 和 JSON,您可能会遇到需要 ? 或其他奇怪的运算符,因此最好只使用它们的等效函数。您可以在psql 控制台中查找它们,例如\doS+ @&gt;

      如参数所述,您的查询不是本机查询。

      select p from Contrat p where...
      

      只有当它到达数据库时才会给你一个错误。

      试试类似的东西

      @Query(nativeQuery = true, value = "select * from Contrat where jsonb_contains(contrat_json, :nom )")
      

      只需将"{\"nom\":\"" + param + "\"}" 绑定为参数

      【讨论】:

      • 用简单的连接操作 JSON 是非常危险的。此外,@&gt; 的对应函数(即jsonb_contains)不能使用contrat_json 上的任何索引。 -- 并且? 操作符无论如何都可以被转义。
      • 好吧,另一种方法是您使用某种 JSON 构建器,但这是一个简化的案例,@&gt; 是 OP 要求的。至于转义?,我在Hibernate 中尝试过。您添加了一级转义,JDBC 驱动程序抱怨未设置的参数,您添加了两级转义,Hibernate 抱怨未设置的参数。无法同时满足两者。
      猜你喜欢
      • 2019-09-19
      • 1970-01-01
      • 2016-11-02
      • 2012-10-09
      • 1970-01-01
      • 2013-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多