【发布时间】:2019-08-26 01:57:45
【问题描述】:
我想使用spring数据存储库接口来执行原生查询-我认为这种方式是最简单的,因为复杂度低。
但是在扩展接口时。 CrudRepository<T, ID> 我需要写 T - 我的实体,它不可用。
我的本机查询不返回任何具体实体,那么在没有实体的情况下创建 spring 存储库的最佳方法是什么?
【问题讨论】:
标签: java spring spring-boot jpa spring-data-jpa
我想使用spring数据存储库接口来执行原生查询-我认为这种方式是最简单的,因为复杂度低。
但是在扩展接口时。 CrudRepository<T, ID> 我需要写 T - 我的实体,它不可用。
我的本机查询不返回任何具体实体,那么在没有实体的情况下创建 spring 存储库的最佳方法是什么?
【问题讨论】:
标签: java spring spring-boot jpa spring-data-jpa
CrudRepository 或 JpaRepository 无法在没有 <Entity,ID> 对的情况下工作。
你最好创建一个自定义仓库,注入 EntityManager 并从那里查询:
@Repository
public class CustomNativeRepositoryImpl implements CustomNativeRepository {
@Autowired
private EntityManager entityManager;
@Override
public Object runNativeQuery() {
entityManager.createNativeQuery("myNativeQuery")
.getSingleResult();
}
}
【讨论】:
CustomNativeRepository,你如何定义它?
您可以只使用@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);
}
}
【讨论】:
如果您使用 JPA,则需要实体。作为之前的答案,您可以直接从 EntityManager 创建 NativeQueries 或使用 Criteria API。
一些关于自定义报告和常见回购行为的文档:
【讨论】:
目前,JPA 中没有创建仅包含本机或 JPQL/HQL 查询的存储库的功能(使用 @Query 表示法)。为了解决这个问题,您可以创建一个虚拟对象以插入到扩展接口中,如下所示:
@Entity
public class RootEntity {
@Id
private Integer id;
}
@Repository
public interface Repository extends JpaRepository<RootEntity, Integer> {
}
【讨论】:
我认为,当您没有用于本机查询结果集的具体实体类时,可以考虑使用 JdbcTemplate 作为替代方案。使用 JdbcTemplate 查询数据需要一个用于结果集的 POJO 类和一个为 POJO 类实现 RowMapper 接口的映射器。
【讨论】:
这对我们有用。见实体管理器
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 注释。
【讨论】: