如何拥有多个弹簧数据JPA存储库的基类



i开发了存储不同时间序列的应用程序,例如温度,压力等。因此,我有一个所有这些测量值的基类:

@MappedSuperclass
public abstract class Entity {
    @Id
    @Column(name = "f_id")
    private UUID id = UUID.randomUUID();
    @Column(name = "f_location_id")
    private UUID locationId;
    @Column(name = "f_time")
    private long time;
    // getters and setters  
}

我需要一种常见的存储库方法来获得一个测量,这是经过的时间,例如:

public T getPrevious(T entity) {
   "SELECT e FROM " + entity.getClass().getSimpleName() + " e WHERE e.time <= :time "
   // only query example here to get you an idea.
}

我关注了春季文档:https://docs.spring.io/spring-data/jpa/jpa/docs/current/current/referent/referent/html/#repositories.custom-behaviour-behaviour-for-for-for-al-all-repositories

但是,该部分告诉我们如何制作所有存储库都具有该方法,但是我不需要 all (我defenityle不希望我的位置reposoritor来有那种方法)。我也不想为每个测量实体实施该方法。

我该怎么办?

答案

接受的答案是正确的,但是我想发布所有代码,因为它显示了如何自动 EntityManager以及如何按运行时通过实体类获取所需存储库。

public interface TemperatureRepository extends TimeSeriesCrudRepository<Temperature> {}
public class TemperatureRepositoryImpl extends TimeSeriesRepositoryImpl<Temperature> {
    public TemperatureRepositoryImpl(EntityManager entityManager) {
        super(entityManager);
    }
}
// this interface is needed to use any TimeSeries repository in common way
@NoRepositoryBean // annotation important
public interface TimeSeriesCrudRepository<T extends TimeSeriesEntity> extends TimeSeriesRepository<T>, CrudRepository<T, UUID> {}
public interface TimeSeriesRepository<T extends TimeSeriesEntity> {
    void getPrevious(T entity);
}
public class TimeSeriesRepositoryImpl<T extends TimeSeriesEntity>  implements TimeSeriesRepository<T> {
    private final EntityManager entityManager;
    public TimeSeriesRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    public void getPrevious(T entity) {
        // impl
    }
}
@Service
public class RepositoriesService {
    private Repositories repositories = null;
    @Autowired
    public RepositoriesService(WebApplicationContext appContext) {
        repositories = new Repositories(appContext);
    }
    // this explains why we need TimeSeriesCrudRepository - to return generic interface with both common CRUD and custom meth
    <T extends TimeSeriesEntity> TimeSeriesCrudRepository<T> getRepository(T entity) {
        //noinspection unchecked
        return (TimeSeriesCrudRepository<T>) repositories.getRepositoryFor(entity.getClass());
    }
}

您可以按照官方文档中所需的存储库添加自定义实现。


让我们说您有这些基本实体:

@MappedSuperclass
public abstract class Entity {
  @Id
  @Column(name = "f_id")
  private UUID id = UUID.randomUUID();
}
@MappedSuperclass
public abstract class TimeSeries extends Entity {
  @JoinColumn(name = "f_location_id")
  @ManyToOne
  private Location location;
  @Column(name = "f_time")
  private long time;
}

以下具体实体:

@Entity
public class Location extends Entity {}
@Entity
public class Temperature extends TimeSeries {}
@Entity
public class Pressure extends TimeSeries {}

和以下基本存储库接口:

public interface EntityRepository<T exends Entity> extends CrudRepository<T, UUID> {}
public interface TimeSeriesRepository<T extends TimeSeries> extends EntityRepository<T> {}

然后,Location(和类似实体)的存储库接口将简单地定义为:

public interface LocationRepository extends EntityRepository<Location> {}

等等。


可以为TimeSeries的后代添加自定义行为:

public interface CustomRepository<T extends TimeSeries> {
  T getPrevious(T entity);
}
public abstract class CustomRepositoryImpl<T extends TimeSeries> implements CustomRepository<T> {
  public T getPrevious(T entity) {
    ...
  }
}
public class TemperatureRepositoryImpl extends CustomRepositoryImpl<Temperature> {}
public interface TemperatureRepository extends TimeSeriesRepository<Temperature>, CustomRepository<Temperature> {}
public class PressureRepositoryImpl extends CustomRepositoryImpl<Pressure> {}
public interface PressureRepository extends TimeSeriesRepository<Pressure>, CustomRepository<Pressure> {}

注意:如果Temperature的存储库称为TemperatureRepository,则必须由名为TemperatureRepositoryImpl的类实现附加的自定义行为,依此类推。这在顶部链接的部分的官方文档中进行了解释。这将迫使弹簧数据基础架构自动发现自定义实现类,并在运行时注入自定义行为。

Spring Doc中所述的解决方案仍然可用于为您的存储库的一个子集提供自定义方法如果您可以将存储库放在单独的软件包中。p>您只需要使用不同的base-class属性指定<jpa:repositories ... />一次。

以下内容告诉Spring使用com.example.repositories.std中的所有存储库以及我自己的自定义基础级的默认基类,用于com.example.repositories.special中的存储库。

<jpa:repositories base-package="com.example.repositories.std"
    entity-manager-factory-ref="emf" />
<jpa:repositories base-package="com.example.repositories.special" base-class="com.example.repositories.special.MyBaseRepositoryImpl"
    entity-manager-factory-ref="emf" />

重要:"特殊"软件包不能嵌套在" std"软件包内,默认基类将提供存储库。

最新更新