我刚开始接触spring-data和spring-data-rest,并且非常想利用这些工具所提供的优势。对于大多数情况,基本功能非常适合我的使用情况,但是有些情况下,我需要自定义底层功能,并选择性地分配一些仓库以继承我所需的定制功能。
为了更好地解释问题,在spring-data中有两个可能从中继承功能的接口,即CrudRepository或PagingAndSortingRepository。我想添加第三个接口,称之为PesimisticRepository。
所有PesimisticRepository要做的就是以不同的方式处理已删除的@Entity概念。一个已删除的实体是其deleted属性为NOT NULL的实体。这意味着可以由PesimisticRepository处理的@Entity必须具有deleted属性。
重写这些方法而不是提供自定义方法(如
此外,我已经阅读了文档,允许您更改所有存储库的默认JpaRepository,但是我需要在每个存储库上执行此操作。希望我已经足够清楚地描述了问题。如果有任何需要更好解释的地方,请在评论区中告诉我。
为了更好地解释问题,在spring-data中有两个可能从中继承功能的接口,即CrudRepository或PagingAndSortingRepository。我想添加第三个接口,称之为PesimisticRepository。
所有PesimisticRepository要做的就是以不同的方式处理已删除的@Entity概念。一个已删除的实体是其deleted属性为NOT NULL的实体。这意味着可以由PesimisticRepository处理的@Entity必须具有deleted属性。
这是完全可能的,我几年前实际上已经实现了这个功能。(如果您感兴趣,可以在这里查看)
我目前使用spring-data的尝试如下:
PagingAndSortingRepository
的扩展
package com.existanze.xxx.datastore.repositories;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.io.Serializable;
@NoRepositoryBean
public interface PesimisticRepository<T,ID extends Serializable> extends PagingAndSortingRepository<T,ID> {
}
我提供了一个继承 JPARepository
的默认实现。
package com.existanze.xxx.datastore.repositories;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.Serializable;
import java.util.Date;
public class JpaPesimisticRepository<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements PesimisticRepository<T,ID> {
private final EntityManager entityManager;
public JpaPesimisticRepository(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
this.entityManager = em;
}
@Override
@Transactional
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
CriteriaBuilder cb = this.entityManager.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = cb.createQuery(getDomainClass());
Root<T> from = criteriaQuery.from(this.getDomainClass());
Predicate deleted = cb.equal(from.get("deleted"), cb.nullLiteral(Date.class));
criteriaQuery.select(from).where(deleted);
TypedQuery<T> query = this.entityManager.createQuery(criteriaQuery);
return pageable == null ? new PageImpl<T>(query.getResultList()) : readPage(query, pageable, spec);
}
}
然后,对于我希望使用悲观方法处理删除的任何bean,我将其定义为此类
package com.existanze.xxx.datastore.repositories;
import com.existanze.xxx.domain.Phone;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface PhoneRepository extends PesimisticRepository<Phone,Integer> {
}
重写这些方法而不是提供自定义方法(如
findAllButDeleted
)的原因很重要。原因是我还希望悲观删除传递到spring-data-rest
,以便生成的HTTP端点不需要任何形式的定制。但是,这似乎仅适用于findAll
方法。然而,对于其余方法,当前异常被抛出。
$ curl http://localhost:8881/phones/23
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 500 </title>
</head>
<body>
<h2>HTTP ERROR: 500</h2>
<p>Problem accessing /phones/23. Reason:
<pre> org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: object is not an instance of declaring class; nested exception is java.lang.IllegalArgumentException: object is not an instance of declaring class</pre></p>
<hr /><i><small>Powered by Jetty://</small></i>
</body>
</html>
此外,我已经阅读了文档,允许您更改所有存储库的默认JpaRepository,但是我需要在每个存储库上执行此操作。希望我已经足够清楚地描述了问题。如果有任何需要更好解释的地方,请在评论区中告诉我。
getRepositoryBaseClass
和getTargetRepository
方法中实现 - 在那里,你或许可以检查传入的RepositoryMetadata
并根据元数据返回不同类型的结果? - demaniak