Java Spring数据:覆盖保存方法
我正在考虑一个项目的spring数据。是否可以覆盖按默认生成的保存方法?如果是,怎么做?没有很好地实现这一点,因此我将所需的逻辑放入服务类中,并保持存储库保存方法不变。我猜您扩展了SimpleParepository:Java Spring数据:覆盖保存方法,java,spring-data,Java,Spring Data,我正在考虑一个项目的spring数据。是否可以覆盖按默认生成的保存方法?如果是,怎么做?没有很好地实现这一点,因此我将所需的逻辑放入服务类中,并保持存储库保存方法不变。我猜您扩展了SimpleParepository: public class **CustomSimpleJpaRepository** extends SimpleJpaRepository { @Transactional public <S extends T> S save(S entity) { //do
public class **CustomSimpleJpaRepository** extends SimpleJpaRepository {
@Transactional
public <S extends T> S save(S entity) { //do what you want instead }
}
public类**customSimpleParepository**扩展了SimpleParepository{
@交易的
public的保存(S实体){//改为执行所需操作}
}
然后,通过扩展以下内容,确保使用此选项而不是默认的SimpleParepository:
public class CustomJpaRepositoryFactory extends JpaRepositoryFactory {
protected <T, ID extends Serializable> JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager entityManager) {
Class<?> repositoryInterface = metadata.getRepositoryInterface();
JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
SimpleJpaRepository<?, ?> repo = isQueryDslExecutor(repositoryInterface) ? new QueryDslJpaRepository(
entityInformation, entityManager) : new CustomSimpleJpaRepository(entityInformation, entityManager);
repo.setLockMetadataProvider(lockModePostProcessor.getLockMetadataProvider());
return repo;
}
}
公共类CustomJpaRepositoryFactory扩展了JpaRepositoryFactory{
受保护的JpaRepository GetTargetRespository(存储元数据元数据,EntityManager EntityManager){
类repositoryInterface=metadata.getRepositoryInterface();
JpaEntityInformation repo=isQueryDslExecutor(repositoryInterface)?新的QueryDslJpaRepository(
entityInformation,entityManager):新的CustomSimpleParepository(entityInformation,entityManager);
setLockMetadataProvider(lockModePostProcessor.getLockMetadataProvider());
回购回报;
}
}
尚未完成,我们还需要您自己的factory bean,以便在配置xml中使用它:
public class CustomRepositoryFactoryBean <T extends JpaRepository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new **CustomJpaRepositoryFactory**(entityManager);
}
公共类CustomRepositoryFactoryBean扩展了JpaRepositoryFactoryBean{
受保护的RepositoryFactorySupport createRepositoryFactory(EntityManager EntityManager){
返回新**CustomJpaRepositoryFactory**(entityManager);
}
}
配置:
<jpa:repositories base-package="bla.bla.dao" factory-class="xxxx.**CustomRepositoryFactoryBean**"/>
希望有帮助。使用JPA事件监听器,如@PrePersist、@PreUpdate。如果底层JPA提供程序支持此功能,这将起作用。这是JPA 2的功能,因此最新的Hibernate、EclipseLink等应该支持它。只需像往常一样创建自定义界面,并在其中声明您要使用与Crudepository(或
JpaRepository
等)公开的相同签名的方法。假设您有一个MyEntity
实体和一个MyEntityRepository
存储库,并且希望覆盖MyEntityRepository
的默认自动生成保存方法,该方法只接受一个实体实例,然后定义:
public interface MyEntityRepositoryCustom {
<S extends MyEntity> S save(S entity);
}
然后,像往常一样,让MyEntityRepository
extendMyEntityRepositoryCustom
执行此操作时,Spring Data JPA将调用MyEntityRepositoryImpl的save
方法,而不是默认实现。
至少在SpringDataJPA1.7.2中的delete
方法中,这对我是有效的
“不明确引用”错误
正如一些评论者所报告的,可能是从某个Spring数据JPA版本或javac版本开始(我不能说它什么时候开始失败,但我肯定它以前工作过)javac编译器开始在重写的方法上给出编译错误:“不明确的引用”。
EclipseJDT不返回此错误,代码在运行时工作,事实上,我之所以打开代码是因为这个原因:要么是javac错误,要么是不符合javac的JDT错误。
也就是说,Lucas在下面发布了解决方案,乍一看可能与上面描述的相同。实际上,区别在于MyEntityRepositoryCustom
,声明必须包含泛型类型
,即使它显然是无用的。因此,如果遇到此错误,请将自定义接口声明更改为:
public interface MyEntityRepositoryCustom<S> {
<S extends MyEntity> S save(S entity);
}
要提供对默认生成的save方法的覆盖,您需要在自己的自定义存储库实现中使用Spring数据存储库实现的聚合
存储库接口:
然后在服务中使用自定义实现:
如果要重用原始方法,这可能会很有帮助。只需在实现类中注入EntityManager
public interface MyEntityRepositoryCustom {
<S extends MyEntity> S save(S entity);
}
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
// optionally specify unitName, if there are more than one
@PersistenceContext(unitName = PRIMARY_ENTITY_MANAGER_FACTORY)
private EntityManager entityManager;
/**
* @see org.springframework.data.jpa.repository.support.SimpleJpaRepository
*/
@Transactional
public <S extends MyEntity> S save(S entity) {
// do your logic here
JpaEntityInformation<MyEntity, ?> entityInformation = JpaEntityInformationSupport.getMetadata(MyEntity.class, entityManager);
if (entityInformation.isNew(entity)) {
entityManager.persist(entity);
return entity;
} else {
return entityManager.merge(entity);
}
}
}
公共接口MyEntityRepositoryCustom{
S save(S实体);
}
公共类MyEntityRepositoryImpl实现MyEntityRepositoryCustom{
//如果有多个unitName,可以选择指定unitName
@PersistenceContext(unitName=PRIMARY\u ENTITY\u MANAGER\u FACTORY)
私人实体管理者实体管理者;
/**
*@请参阅org.springframework.data.jpa.repository.support.simplejpeparepository
*/
@交易的
公共存储(S实体){
//你的逻辑在这里吗
JpaEntityInformation entityInformation=JpaEntityInformationSupport.getMetadata(MyEntity.class,entityManager);
if(entityInformation.isNew(实体)){
entityManager.persist(实体);
返回实体;
}否则{
返回entityManager.merge(实体);
}
}
}
如果仅使用接口,则可以使用默认方法对crudepository
或JpaRepository
进行简单重写:
public interface MyCustomRepository extends CrudRepository<T, ID> {
@Override
default <S extends T> S save(S entity)
{
throw new UnsupportedOperationException("writes not allowed");
}
}
公共接口MyCustomRepository扩展了Crudepository{
@凌驾
默认S保存(S实体)
{
抛出新的UnsupportedOperationException(“不允许写入”);
}
}
我在OpenJDK 11上使用Spring Boot 2.1.4,并且不断从编译器中获得不明确的引用
错误(尽管我的IDE使用的Eclipse JDT编译器没有问题,所以我直到尝试在IDE外部构建它时才发现这个问题)
基本上,我在扩展接口中定义了一个不同名称的方法,然后在调用正常的save()
时,在主存储库接口中使用default
覆盖来调用它
以下是一个例子:
像往常一样为自定义逻辑定义接口:
公共接口MyEntityRepositoryCustomSaveAction{
公共MyEntity(MyEntity实体);
}
让您的存储库扩展该接口:
公共接口MyEntityRepository扩展了JpaRepository,
迈恩
public interface UserRepository extends CrudRepository<User, String>{
}
@Repository("customUserRepository")
public class CustomUserRepository implements UserRepository {
@Autowired
@Qualifier("userRepository") // inject Spring implementation here
private UserRepository userRepository;
public User save(User user) {
User user = userRepository.save(entity);
// Your custom code goes here
return user;
}
// Delegate other methods here ...
@Override
public User findOne(String s) {
return userRepository.findOne(s);
}
}
@Autowired
@Qualifier("customUserRepository")
private UserRepository userRepository;
public interface MyEntityRepositoryCustom {
<S extends MyEntity> S save(S entity);
}
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
// optionally specify unitName, if there are more than one
@PersistenceContext(unitName = PRIMARY_ENTITY_MANAGER_FACTORY)
private EntityManager entityManager;
/**
* @see org.springframework.data.jpa.repository.support.SimpleJpaRepository
*/
@Transactional
public <S extends MyEntity> S save(S entity) {
// do your logic here
JpaEntityInformation<MyEntity, ?> entityInformation = JpaEntityInformationSupport.getMetadata(MyEntity.class, entityManager);
if (entityInformation.isNew(entity)) {
entityManager.persist(entity);
return entity;
} else {
return entityManager.merge(entity);
}
}
}
public interface MyCustomRepository extends CrudRepository<T, ID> {
@Override
default <S extends T> S save(S entity)
{
throw new UnsupportedOperationException("writes not allowed");
}
}
public interface MyCustomRepository<T> {
<S extends T> S save(S entity);
}
public class MyCustomRepositoryImpl implements MyCustomRepository<MyBean> {
@Autowired
private EntityManager entityManager;
@Override
public <S extends MyBean> S save(S entity) {
/**
your custom implementation comes here ...
i think the default one is just
return this.entityManager.persist(entity);
*/
}
}
@RepositoryRestResource
@Repository
public interface MyBeanRepository extends PagingAndSortingRepository<MyBean, Long>, MyCustomRepository<MyBean> {}
public interface MyRepo extends JpaRepository<MyType, Long>, MyRepoCustom{
//Implemented in MyRepoCustom
public MyType save(MyType mytypeEntity);
}
public interface MyRepoCustom{
public MyType save(MyType mytypeEntity);
}
@Repository
public class MyRepoImpl implements MyRepoCustom{
@PersistenceContext
private EntityManager em;
@Transactional
public MyType save(MyType mytypeEntity) {
//type safe implementation
}
}
interface ScoreRepositoryCustom {
Score save(Score score);
}
interface ScoreRepositoryCustom<T> {
<S extends T> S save(S to);
}