【问题标题】:Using SpringBoot CrudRepository to find one known entry使用 SpringBoot CrudRepository 查找一个已知条目
【发布时间】:2017-05-29 20:18:22
【问题描述】:

我目前正在处理一个使用 SpringBoot 的项目。

我使用 Hibernate 创建了一个名为 configuration_documents 的表格。这个表可以存储我创建的不同类型的文档对象。

我创建的文档对象之一是索引,我想检索索引数据,所以我创建了一个这样的存储库:

public interface IndexRepository extends CrudRepository<Index, Long> {
}

我知道配置文档表应该只有一个索引条目,否则只返回表中的第一个索引。实现这一点的最佳方法是什么?

在不修改 IndexRepository 的情况下,我目前正在考虑这样的事情(IndexRepository 是自动插入的):

StreamSupport.stream(this.configurationRepository.findAll().spliterator(), false).
                map(
                    return Index;
                ).//A Collector here perhaps?

谢谢。

【问题讨论】:

  • 所以如果我没看错的话,你可以在同一个表中拥有不同的配置文档类型,对吧?
  • @NiVeR 是的,对于每个文档,我都有一个不同的存储库。谢谢。
  • 使用 findAll() 意味着您将把该类型的所有文档提取到内存中,然后对它们进行操作。通常最好选择要在查询中获取的文档。例如,如果您的表有 50,000 个文档,其中 10,000 个是 Index 类型,并且您对其中 1 个感兴趣,那么最好只获取那个文档而不是 10,000 或 50,000 个文档。要使用 Spring 执行此操作,您将使用 findBy... 方法。如果您提供表和实体定义,我可以向您展示如何做到这一点。

标签: java hibernate spring-boot repository


【解决方案1】:

因此,据我所知,您无法使用jpa 根据行号进行查询。在jpa 中,您必须指定By 参数作为where 子句。请参阅official documentation 了解您可以编写的查询方法。

【讨论】:

    【解决方案2】:

    您可以在构建查询时使用TopFirst 关键字,此处为is the documentation

    你必须像这样声明方法:

    Index findFirstIndex();
    

    IndexRepository 中,这将解决您的问题。

    或者,如果您不允许修改 IndexRepository,您可以使用流 API 以某种方式获取第一个结果

    indexRepository.findAll().stream()
            .findFirst()
            .orElseThrow(
                    () -> new IndexNotFoundException("Index cannot be found")
            );
    

    但第一个选项会更理想。

    【讨论】:

      【解决方案3】:

      首先我建议你考虑一下你将来想用那个Index做什么。 如果它只是只读的不可变实体,那么最好的选择可能是在应用程序启动后(例如使用原始 EntityManager)让一些“IndexHolder”组件将实体注入其中,并使用该组件在整个应用程序中访问Index

      但我假设您也希望能够更新Index。 所以在这种情况下,我可以建议扩展org.springframework.data.repository.Repository 而不是CrudRepository。它会将Index 实体上可能的操作集限制为 NONE,但我们仍然可以使用 spring-data 功能。

      所以存储库可能如下所示:

      // Can only insert/update index entity for now
      interface IndexRepository extends Repository<Index, String> {
      
          Index save(Index index);
      }
      

      显然这还不够,我们至少需要一个检索操作。 在这里,我建议依靠一些fixed ID 来获取Index。 它可能是超出序列范围或 '0' 或 guid 的某个值(取决于您使用的内容)。

      然后我们需要在所有与该实体的持久性操作中强制使用此 ID,但结果查询将快速而简单。

      我想你正在像这样为你的类建模:

      @Entity
      @Table(name = "configuration_documents")
      @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
      @DiscriminatorColumn(name = "type")
      @DiscriminatorValue("DOCUMENT")
      public class ConfigurationDocument {
          @Id
          private String id;
      
          public void setId(String id) {
              this.id = id;
          }
      }
      
      @Entity(name = "Index")
      @DiscriminatorColumn(name = "type")
      @DiscriminatorValue("INDEX")
      public class Index extends ConfigurationDocument {
          ...
      }
      

      让我们添加固定的 id:

      @Entity(name = "Index")
      @DiscriminatorColumn(name = "type")
      @DiscriminatorValue("INDEX")
      @EntityListeners(Index.IndexPersistentId.class)
      public class Index extends ConfigurationDocument {
          //This is going to be our fixed id.
          public static final String INDEX_ID = "42";
      
          public static class IndexPersistentId {
              @PrePersist
              public void prePersist(Index index) {
                  index.setId(INDEX_ID); //enforce using fixed ID
              }
          }
      }
      

      最后一步是向存储库添加检索操作:

      interface IndexRepository extends Repository<Index, String> {
          @Query("select i from Index i where i.id = :#{T(com.stackoverflow.so44249828.Index).INDEX_ID}")
          Index load();
      
          Index save(Index index);
      }
      

      【讨论】:

        【解决方案4】:

        在 spring jpa 中,您可以限制结果如下所示:

        public interface IndexRepository extends CrudRepository<Index, Long> {
        
                   Index findFirstByOrderByIdAsc();
            }
        

        参考

        http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.limit-query-result

        【讨论】:

          【解决方案5】:

          我记得看到过类似于您正在搜索的内容。但是再也找不到那个来源了。

          您仍然可以保留与现在相同的存储库:

          public interface IndexRepository extends CrudRepository<Index, Long> {
          }
          

          对于流部分,你可以做一个Index类的过滤器实例,并在同一行代码中同时获取它的第一个实例,像这样:

          Optional<Index> optional = StreamSupport.stream(repository.findAll().sliterator(), false)
                                                  .filter(i -> i instanceof Index)
                                                  .findFirst();
          

          这应该是最直接的你的要求。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-09-03
            • 1970-01-01
            • 2016-11-23
            • 1970-01-01
            • 2014-07-31
            • 1970-01-01
            • 2016-09-15
            • 2020-01-31
            相关资源
            最近更新 更多