我在 Spring Boot 中使用 Spring Data JPA 有一个数据 model,称为 Player。这代表体育运动中的一个人,该球员有一个名为 jerseyNumber (数字)和位置(他在哪里打球、中锋、防守等)的属性。随着他职业生涯的发展,这些属性具有不同的价值。一个赛季他打8号球,另一个赛季打7号球。
Player name 1
jerseyNumber 8 - Position center - 01.01.2020-31.12.2020
jerseyNumber 7 - Position attacker - 01.01.2021-Present
如何设置 Spring Data JPA 来处理我想知道特定日期的确切状态的查询?假设我想知道 2020 年 6 月 1 日模型的详细信息。
我正在使用 Postgres。
这是我认为的一个选择。
我省略了从存储库中提取播放器并计算当前状态的服务代码。基本上遍历每个字段并根据提供的时间戳确定当前状态,并从中返回一个单独的 DTO 模型。这是一个好方法吗?
我有点担心这些是我最需要急切执行的连接查询。我正在考虑将此数据存储在玩家表中的 JSONB 列中。我的 API 需要在一次响应中为潜在的一百名玩家提供服务。这个示例有点简化,因为这种模式也存在于应用程序中的不同实体周围(查询哪些球队在特定时间点拥有哪些球员等)
@Entity
public class Player {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "player")
private List<PlayerNumber> playerNumbers = new ArrayList<>();
// Getters and setters
}
@Entity
public class PlayerNumber {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int number;
private LocalDate startDate;
private LocalDate endDate;
@ManyToOne
private Player player;
// Getters and setters
}
我想说你的数据模型是一个很好的方法,但是通过使用服务或急切加载在特定时间点获取玩家的想法不是。 我们会解决您关心的每一个问题。
select *
from player_number pn
join player p on pn.player_id = p.id
where pn.start_date < :date
and (pn.end_date > :date or pn.end_date is null) // Suspect null is present
spring-data-jpa
有多种方法可以实现这一点,请参考这个doc示例public interface PlayerNumberRepository extends JpaRepository<PlayerNumber, Long> {
@Query("SELECT p FROM PlayNumber p WHERE p.startTime <= ?1 and (p.endTime >= ?1 or p.endTime is null)")
List<FuelPrice> findInSpecificPointInTime(LocalDate pointInTime);
}
Proxy projection
又名自定义 dto,也可以应用分页。示例public interface PlayerDto {
Long getId();
int getNumber();
// All getters properties
}
并将其应用到存储库
public interface PlayerNumberRepository extends JpaRepository<PlayerNumber, Long> {
@Query(nativeQuery = true,
value="select p.id as id, pn.number as number
from player_number pn
join player p on pn.player_id = p.id
where pn.start_date < :date
and (pn.end_date > :date or pn.end_date is null)")
List<PlayerDto> findInSpecificPointInTime(LocalDate pointInTime);
}
这是示例,希望有帮助。