创建没有实体的spring存储库
Posted
技术标签:
【中文标题】创建没有实体的spring存储库【英文标题】:Create spring repository without entity 【发布时间】:2019-08-26 01:57:45 【问题描述】:我想使用spring数据存储库接口来执行原生查询-我认为这种方式是最简单的,因为复杂度低。
但是在扩展接口时。 CrudRepository<T, ID>
我需要写 T - 我的实体,它不可用。
我的本机查询不返回任何具体实体,那么在没有实体的情况下创建 spring 存储库的最佳方法是什么?
【问题讨论】:
【参考方案1】:CrudRepository
或 JpaRepository
无法在没有 <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 注释。
【讨论】:
以上是关于创建没有实体的spring存储库的主要内容,如果未能解决你的问题,请参考以下文章
在 Java 或 Grails 应用程序中动态创建实体、Spring 存储库和 facelets 页面
在 Spring Data JPA 中,如何在运行时添加实体?