Java Spring数据:覆盖保存方法

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

我正在考虑一个项目的spring数据。是否可以覆盖按默认生成的保存方法?如果是,怎么做?

没有很好地实现这一点,因此我将所需的逻辑放入服务类中,并保持存储库保存方法不变。

我猜您扩展了SimpleParepository:

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
extend
MyEntityRepositoryCustom

执行此操作时,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);
}