Spring Data:覆盖保存方法

beg*_*er_ 36 java spring-data

我正在考虑项目的弹簧数据.是否可以覆盖每个默认生成的保存方法?如果是,怎么样?

Mau*_*ari 31

只需像往常一样创建自定义界面,并在那里声明要使用与CrudRepository(或JpaRepository等)公开的方法相同的签名进行ovverride的方法.假设您有一个MyEntity实体和一个MyEntityRepository存储库,并且您希望覆盖默认的自动生成save方法,MyEntityRepository该方法只接受一个实体实例,然后定义:

public interface MyEntityRepositoryCustom {
  <S extends MyEntity> S save(S entity);
}
Run Code Online (Sandbox Code Playgroud)

像MyEntityRepositoryImpl往常一样,在你的喜欢中实现这个方法:

@Transactional
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
  public <S extends MyEntity> S save(S entity) {
    // your implementation
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,像往常一样,让MyEntityRepository实施MyEntityRepositoryCustom.

这样做,Spring Data JPA将调用save您的方法MyEntityRepositoryImpl而不是默认实现.至少这对我来说适用delete于Spring Data JPA 1.7.2中的方法.

  • 我只是得到这个错误:java:`对save的引用是不明确的 (18认同)
  • 这个确实有效.使其工作的重要一点是保留命名约定.即,MyEntityRepositoryImpl类名必须像`<主储存库接口名称> Impl`和_not_如例如`MyEntityRepositoryCustomImpl`来构建.它不适用于后一种情况. (7认同)
  • 很酷,但是如何从MyEntityRepositoryImpl调用默认的JPARepository.save方法? (5认同)
  • 这在带有“模糊引用”错误的 Spring Boot 2.1.1 中不起作用。 (3认同)
  • @DanielPinyol你让Spring在你的`MyEntityRepositoryImpl`中注入实体管理器,然后在它上面调用`persist(Object)`,而不是默认的`JPARepository`实现.您可以使用`@ PersistenceContext`来实现此目的. (2认同)
  • 我刚刚发布了覆盖保存方法的正确方法 (2认同)

beg*_*er_ 8

没有得到这个很好地工作所以我把我需要的逻辑放入一个服务类,并保持存储库保存方法不变.


Bal*_*ban 8

我想你扩展SimpleJpaRepository:

public class **CustomSimpleJpaRepository** extends SimpleJpaRepository {

@Transactional
public <S extends T> S save(S entity) { //do what you want instead }
}
Run Code Online (Sandbox Code Playgroud)

然后通过扩展来确保使用它而不是默认的SimpleJpaRepository:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

还没有完成,我们还需要你自己的工厂bean在config 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);
}
Run Code Online (Sandbox Code Playgroud)

}

配置:

<jpa:repositories base-package="bla.bla.dao" factory-class="xxxx.**CustomRepositoryFactoryBean**"/>
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.


小智 8

要提供对默认生成的save方法的覆盖,您需要在自己的自定义存储库实现中使用Spring Data存储库实现的聚合.

存储库界面:

public interface UserRepository extends CrudRepository<User, String>{

}
Run Code Online (Sandbox Code Playgroud)

您的存储库实现:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的服务中使用您的自定义实现:

@Autowired
@Qualifier("customUserRepository")
private UserRepository userRepository;
Run Code Online (Sandbox Code Playgroud)

  • 不错的 :) 我只是在原始 Spring Repository 上使用了一个 `Qualifier`,并用 `@Primary` 注释了我的覆盖版本以防止在任何地方使用名称! (3认同)

Luc*_*cas 7

为了正确覆盖 save 方法,您必须创建一个接口,该接口具有在 CrudRepository 上声明的原始方法的正确签名,包括泛型

public interface MyCustomRepository<T> {
    <S extends T> S save(S entity);
}
Run Code Online (Sandbox Code Playgroud)

然后,创建您的实现(后缀 Impl 在类名中很重要)

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);
       */
    }

}
Run Code Online (Sandbox Code Playgroud)

最后,使用之前创建的界面扩展您的存储库

@RepositoryRestResource
@Repository
public interface MyBeanRepository extends PagingAndSortingRepository<MyBean, Long>, MyCustomRepository<MyBean> {}
Run Code Online (Sandbox Code Playgroud)


Eri*_*ond 6

我在 OpenJDK 11 上使用 Spring Boot 2.1.4 并且还不断ambiguous reference从编译器收到错误(尽管我的 IDE 使用的 Eclipse JDT 编译器没有问题,所以我没有发现这个问题,直到我尝试构建它在我的 IDE 之外)。

我基本上最终在我的扩展接口中定义了一个具有不同名称的方法,然后default在我的主存储库接口中使用覆盖来在调用正常时调用它save()。

下面是一个例子:

像往常一样定义自定义逻辑的接口:

public interface MyEntityRepositoryCustomSaveAction {
    public MyEntity saveSafely(MyEntity entity);
}
Run Code Online (Sandbox Code Playgroud)

使您的存储库扩展该接口:

public interface MyEntityRepository extends JpaRepository<MyEntity, MyEntityId>,
  MyEntityRepositoryCustomSaveAction {

    @Override
    @SuppressWarnings("unchecked")
    default MyEntity save(MyEntity entity)
    {
        return saveSafely(entity);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们已经覆盖了 save() from JpaRepository(嗯,真的CrudRepository是JpaRepository扩展)来调用我们的自定义方法。编译器会警告未经检查的转换,所以如果你想用@SuppressWarnings.

使用自定义逻辑遵循 Impl 类的约定

public class MyEntityRepositoryCustomSaveActionImpl implements 
  MyEntityRepositoryCustomSaveAction {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public MyEntity saveSafely(MyEntity entity) {
       //whatever custom logic you need
    }

}
Run Code Online (Sandbox Code Playgroud)


ytt*_*rrr 5

如果您要重用原始方法,这可能会很有帮助。只需注入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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


M.P*_*cia 5

如果您仅使用接口,则可以使用默认方法对CrudRepositoryor进行简单覆盖JpaRepository:


public interface MyCustomRepository extends CrudRepository<T, ID> {

  @Override
  default <S extends T> S save(S entity)
  {
    throw new UnsupportedOperationException("writes not allowed");
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我想调用 super.save 怎么办? (6认同)