【问题标题】:Spring JPA Repository Custom QuerySpring JPA 存储库自定义查询
【发布时间】:2017-11-15 15:56:25
【问题描述】:

此自定义查询有效(这只是说明问题的基本查询):

public interface BookQueryRepositoryExample extends Repository<Book, Long> {
    @Query(value = "select * from Book b where b.name=?1", nativeQuery = true)
    List<Book> findByName(String name);
}

但我需要另一个自定义查询,其中 where 子句将在调用该方法之前动态构造。

public interface BookQueryRepositoryExample extends Repository<Book, Long> {
    @Query(value = "select * from Book b where ?1", nativeQuery = true)
    List<Book> findByWhatever(String qry);
}

但我无法让它工作。有什么解决办法吗?

更新日期:2017 年 6 月 16 日

只想提一下,我正在搜索的字段是“非规范化”形式。这些值可能看起来像这些(如下)。所以我的查询有一系列类似的语句

样本 1:

name:John Smith;address1:123 Xyz St;city:New York;zip:12345;country:USA;id:ABC1234;email:js@abc.com;

示例 2:重新排列

address1:123 Xyz St;zip:12345;email:js@abc.com;name:John Smith;country:USA;id:ABC1234;city:New York;

示例 3:缺少字符串/文本

zip:12345;email:js@abc.com;name:John Smith;id:ABC1234;city:New York;

【问题讨论】:

  • 不,因为这不是参数替换的工作方式。为什么不使用 JPQL 或 Criteria 查询来进行动态查询。 (您的第一个自定义查询甚至不需要findByName 方法就足以实现您想要的。
  • 好的。将调查该标准查询。谢谢。我并没有真正使用 findByName 方法。我只是把它放在那里是为了强调。
  • 你可以访问这个答案stackoverflow.com/a/50365522/3073945

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


【解决方案1】:

这行不通,至少用这种方法不行。

查询中的占位符不只是被一些任意的String 替换,而是变量,只能代表您在其他情况下作为文字提供的内容。

但是作为@M。 Deinum 指出还有其他选择:您可以 write a custom method 并使用

  • JPA 标准 API
  • JPQL
  • 规格
  • 查询DSL

有关示例,请参阅本文:https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/

【讨论】:

    【解决方案2】:

    例如,如果您想根据作者姓名、标题和成本等属性的组合查找图书,则可以使用以下查询

    public interface BookQueryRepositoryExample extends Repository<Book, Long> { @Query(value = "select * from Book b where (?1 or null) and (?2 or null) and (?3 or null) ", nativeQuery = true ) List<Book> findByWhatever(String authorName,String title,Double cost); }

    【讨论】:

      【解决方案3】:

      解决这个问题的方法是,您可以有一个类来通过注入EntityManager 来执行动态查询,如下所示:

      //Pseudo code
      @Repository
      public class SomeDao {
      
          @PersistenceContext
          private EntityManager entityManager;
          
          public List<Book> findByWhatever(String qry){
              Query q = entityManager.createNativeQuery(qry);
              List<Object[]> books = q.getResultList();
      
              // Your logic goes here
      
              // return something
          }
      }
      

      【讨论】:

      • 我需要使用 springframework Repository 或 JpaRepository 来实现它。有什么想法吗?
      • JPARepository,我很久以前就尝试过,但运气不好。后来实现如上所示。因为Spring-Boot 可以在任何需要的地方注入EnityManager。这不需要额外的配置。您也可以使用 Criteria's
      • 在 JPARepository 文档中没有提到他们关于传递动态查询的内容。我认为需要做一些技巧
      【解决方案4】:

      您可以使用 spring-data 提供的规范接口创建动态 where 子句。

      这里有一个链接:https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/

      【讨论】:

        【解决方案5】:

        @Query(value = "select * from Book b where ?1", nativeQuery = true) 列出 findByWhatever(String qry);

        首先,不推荐你的方法,很可能会导致SQL注入漏洞(如果你没有以正确的方式处理'qry'参数)。

        其次,您正在尝试重新发明轮子。正如@Jens Schauder 在他的回答中已经提到的那样,有很多可能的方式来实现动态查询。如果您不需要复杂的东西,我将再添加一种似乎是最简单的方法。它叫做“Query by Example”。

        public interface BookRepository extends JpaRepository<Book, Long>{
        }
        

        然后,您创建一个看起来像您要查找的对象的实例,这意味着您必须设置用于生成动态查询的属性:

        Book book = new Book();
        book.setYear(2015);
        book.setPublisher("O'Realy")
        
        Example<Book> bookExample = Example.of(book);
        

        最后一步是将您的示例对象传递给 Spring Data JPA 存储库:

        List<Book> books = bookRepository.findAll(bookExample);
        

        因此,您将获得 O'Realy 于 2015 年出版的书籍列表。它的好处是您可以添加更多字段以在运行时搜索,只需将其设置为book 实例。

        如果你需要比精确值匹配更复杂的东西,你可以使用匹配器。在下面的示例中,Spring Data JPA 将搜索名称以“O”开头的所有书籍,忽略大小写。

        Book book = new Book();
        book.setName("O")
        
        ExampleMatcher matcher = ExampleMatcher.matching().
            .withMatcher("publisher", startsWith().ignoreCase());
        
        Example<Book> bookExample = Example.of(book, matcher);
        
        List<Book> books = bookRepository.findAll(bookExample);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-01
          • 2019-06-17
          • 2018-10-06
          • 2016-08-29
          • 1970-01-01
          • 1970-01-01
          • 2015-10-29
          • 2021-04-16
          相关资源
          最近更新 更多