Java 如何覆盖Spring数据JPA存储库基方法?

Java 如何覆盖Spring数据JPA存储库基方法?,java,spring,hibernate,spring-data-jpa,Java,Spring,Hibernate,Spring Data Jpa,我有一些实体类型在保存时需要额外的逻辑(确切地说,我想在保存时保存位置)。我不想使用任何特定于DB的特性,比如触发器,因为我不确定将来会使用什么样的数据存储 所以我想重写save()方法 在Spring Data JPA文档中,我可以看到为存储库类提供自己实现的两种方法: 扩展基本存储库类并告诉Spring数据使用它 使用实现类(PositionedRepositoryImpl)定义接口(在我的例子中,我假设PositionedRepository) 第一种方法的问题-我不想为所有存储库实现它,

我有一些实体类型在保存时需要额外的逻辑(确切地说,我想在保存时保存位置)。我不想使用任何特定于DB的特性,比如触发器,因为我不确定将来会使用什么样的数据存储

所以我想重写
save()
方法

在Spring Data JPA文档中,我可以看到为存储库类提供自己实现的两种方法:

  • 扩展基本存储库类并告诉Spring数据使用它
  • 使用实现类(
    PositionedRepositoryImpl
    )定义接口(在我的例子中,我假设
    PositionedRepository
  • 第一种方法的问题-我不想为所有存储库实现它,只定位了两种实体类型

    第二种方法的问题——我没有访问基本存储库方法的权限,所以除了位置计算之外,我还需要以某种方式构建所有查询,通常由基本存储库提供


    是否可以仅为特定存储库类型扩展基本存储库类?

    作为第三个选项,您可以扩展实现
    JpaRepository
    JpaSpecificationExecutor
    simplejpepository
    。 通过这种方式,您可以受益于
    JpaRepository
    的默认实现,同时能够覆盖这些方法

    例如:

    @Repository
    public class PositionedRepository extends SimpleJpaRepository<Positioned, Long>  {
    
        @Override
        public Positioned save(Positioned positioned) {
               ...
        }
    
    }
    
    @存储库
    公共类定位存储扩展了SimpleParepository{
    @凌驾
    公共定位保存(定位){
    ...
    }
    }
    

    作为第四个选项,您还可以定义自己的
    savePositioned()
    方法,该方法在后台使用
    JpaRepository.save()
    不要在存储库本身中执行该逻辑。将存储库视为java和数据库之间的哑层。它只是将数据从一端传递到另一端

    相反,您应该在不同的层中处理这种情况。一个更聪明的。业务逻辑层

    请参见此示例:

    @Service
    public class MyEntityService{
    
         private final MyEntityRepository myEntityRepository;
         private final OtherEntityRepository otherEntityRepository;
    
         @Autowired
         public MyEntityService(MyEntityRepository myEntityRepository, 
                              OtherEntityRepository otherEntityRepository){
             this.myEntityRepository = myEntityRepository;
             this.otherEntityRepository = otherEntityRepository;
         }
    
         public void save(MyEntity myEntity){
              // do stuff with otherEntityRepository
              myEntitiyRepository.save(myEntity);
         }
    }
    
    你可以:

    public class CustomJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> {
      private final JpaEntityInformation<T, ?> entityInformationWrap;
      private final EntityManager emWrap;
      public CustomJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        entityInformationWrap=entityInformation;
        emWrap=entityManager;
      }
    
      @Override
      public <S extends T> S save(S entity) {
        //doing
      }
    
    }
    
    public类CustomJpaRepository扩展了SimpleJpaRepository{
    私人最终JpaEntityInformation entityInformationWrap;
    私有最终实体管理器emWrap;
    公共客户jparepository(JpaEntityInformation、EntityManager、EntityManager){
    超级(实体信息、实体管理器);
    entityInformationWrap=entityInformation;
    emWrap=实体管理器;
    }
    @凌驾
    公共存储(S实体){
    //做
    }
    }
    
    然后主类添加:
    @EnableJpaRepositories(repositoryBaseClass=CustomJpaRepository.class)

    回答得很好!但是
    EntityManager
    并不是最好的名字,因为它代表了JPA中非常具体的东西
    PositionedService
    要保持通用性就更清楚了:)我将我的存储库公开为Spring数据REST端点,希望它保持在默认Spring流中。我将我的存储库公开为Spring数据REST端点。它可能会起作用,但非常令人沮丧。我建议在数据库和客户端之间至少有3层:数据访问层->存储层,业务逻辑层->服务,通信层->控制器。这样的话,你显然已经把责任分开了。通信处理请求并调用业务逻辑,然后业务逻辑调用数据访问。如果您像这样构建应用程序,您将不胜感激