【问题标题】:Create spring repository without entity创建没有实体的spring存储库
【发布时间】:2019-08-26 01:57:45
【问题描述】:

我想使用spring数据存储库接口来执行原生查询-我认为这种方式是最简单的,因为复杂度低。

但是在扩展接口时。 CrudRepository<T, ID> 我需要写 T - 我的实体,它不可用。

我的本​​机查询不返回任何具体实体,那么在没有实体的情况下创建 spring 存储库的最佳方法是什么?

【问题讨论】:

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


    【解决方案1】:

    CrudRepositoryJpaRepository 无法在没有 <Entity,ID> 对的情况下工作。

    你最好创建一个自定义仓库,注入 EntityManager 并从那里查询:

      @Repository
      public class CustomNativeRepositoryImpl implements CustomNativeRepository {
    
        @Autowired
        private EntityManager entityManager;
    
        @Override
        public Object runNativeQuery() {
            entityManager.createNativeQuery("myNativeQuery")
             .getSingleResult();
        }
    }
    

    【讨论】:

    • 这不是完整的代码。什么是CustomNativeRepository,你如何定义它?
    • 在这种情况下只是一个具有公共 Object runNativeQuery() 方法的接口
    • 为了完整性添加那个简单的sn-p会更好
    • 或者更好的是,没有接口。
    • 虽然这个答案似乎是正确的,但我不明白为什么 Spring 不允许在其上使用 @Repository 和在方法上使用 @Query 的接口。
    【解决方案2】:

    您可以只使用@Repository 注释您的实现,并获得一个EntityManager 的实例。

    public interface ProductFilterRepository {
        Page<Product> filter(FilterTO filter, Pageable pageable);
    }
    
    
    
    @Repository
    @AllArgsConstructor
    public class ProductFilterRepositoryImpl implements ProductFilterRepository {
    
        private final EntityManager em;
    
        @Override
        public Page<Product> filter(FilterTO filter, Pageable pageable) {
            CriteriaBuilder cb = em.getCriteriaBuilder();
            CriteriaQuery<Product> cq = cb.createQuery(Product.class);
            Root<Product> root = cq.from(Product.class);
            List<Predicate> predicates = new ArrayList<>();
    
            if (filter.getPriceMin() != null) {
                predicates.add(cb.ge(root.get("price"), filter.getPriceMin()));
            }
            if (filter.getPriceMax() != null) {
                predicates.add(cb.le(root.get("price"), filter.getPriceMax()));
            }
            if (filter.getBrands() != null && !filter.getBrands().isEmpty()) {
                predicates.add(root.get("brand").in(filter.getBrands()));
            }
            if (filter.getCategories() != null && !filter.getCategories().isEmpty()) {
                predicates.add(root.get("category").in(filter.getCategories()));
            }
            cq.where(predicates.toArray(new Predicate[0]));
            TypedQuery<Product> tq = em.createQuery(cq);
            tq.setMaxResults(pageable.getPageSize());
            tq.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
    
            CriteriaQuery<Long> countCq = cb.createQuery(Long.class);
            countCq.select(cb.count(countCq.from(Product.class)));
            countCq.where(predicates.toArray(new Predicate[0]));
            TypedQuery<Long> countTq = em.createQuery(countCq);
            Long count = countTq.getSingleResult();
    
            return new PageImpl<>(tq.getResultList(), pageable, count);
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果您使用 JPA,则需要实体。作为之前的答案,您可以直接从 EntityManager 创建 NativeQueries 或使用 Criteria API。

      一些关于自定义报告和常见回购行为的文档:

      https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html#repositories.custom-behaviour-for-all-repositories

      【讨论】:

        【解决方案4】:

        目前,JPA 中没有创建仅包含本机或 JPQL/HQL 查询的存储库的功能(使用 @Query 表示法)。为了解决这个问题,您可以创建一个虚拟对象以插入到扩展接口中,如下所示:

        @Entity
        public class RootEntity {
            @Id
            private Integer id;
        }
        
        @Repository
        public interface Repository extends JpaRepository<RootEntity, Integer> {
        }
        

        【讨论】:

        • 这是一些奇怪的代码。它甚至不会编译。接口上的私有修饰符?好吧,也许这是一个错字。但是即使将接口更改为类也不会让您的 Spring 应用程序运行。
        • 是的,这是一个错字,现在应该可以了。如果您遇到问题,您能否提供错误消息,或打开另一个问题?
        【解决方案5】:

        我认为,当您没有用于本机查询结果集的具体实体类时,可以考虑使用 JdbcTemplate 作为替代方案。使用 JdbcTemplate 查询数据需要一个用于结果集的 POJO 类和一个为 POJO 类实现 RowMapper 接口的映射器。

        【讨论】:

        • 这是一种不好的方法。例如,您能否快速回答这个问题:这样的混合应用程序将使用多少个事务管理器?
        【解决方案6】:

        这对我们有用。见实体管理器

        https://www.baeldung.com/hibernate-entitymanager

        @Repository
        public class MyRepository {
        
            @PersistenceContext
            EntityManager entityManager;
        
            public void doSomeQuery(){
                Query query = entityManager.createNativeQuery("SELECT foo FROM bar");
                query.getResultsList()
                ...
            }
        
        }
        

        顺便说一句,我认为这里甚至不需要 @Repository 注释。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-02-01
          • 2015-12-04
          • 1970-01-01
          • 2019-07-08
          • 1970-01-01
          • 1970-01-01
          • 2020-07-12
          相关资源
          最近更新 更多