Tôi muốn biết cách triển khai temporal tables trong JPA 2 với EclipseLink. Theo thời gian, tôi có nghĩa là các bảng xác định thời hạn hiệu lực. Một vấn đề mà tôi đang phải đối mặt là các bảng tham chiếu có thể không còn các ràng buộc khoá ngoài đối với các bảng được tham chiếu (bảng tạm thời) vì bản chất của các bảng được tham chiếu mà bây giờ các khóa chính của chúng bao gồm thời hạn hiệu lực.Làm thế nào để thực hiện một bảng thời gian bằng cách sử dụng JPA?
- Tôi làm cách nào để ánh xạ mối quan hệ giữa các thực thể của tôi?
- Điều đó có nghĩa là các thực thể của tôi không thể có mối quan hệ với những thực thể hợp lệ nữa không?
- Liệu sự có trách nhiệm để khởi tạo các mối quan hệ hiện tại do tôi làm theo cách thủ công trong một số loại Dịch vụ hoặc DAO chuyên biệt?
Điều duy nhất tôi tìm thấy là khung được gọi là DAO Fusion đề cập đến điều này.
- Có cách nào khác để giải quyết vấn đề này không?
- Bạn có thể cung cấp ví dụ hoặc tài nguyên về chủ đề này (JPA với cơ sở dữ liệu thời gian) không?
Đây là một ví dụ hư cấu về mô hình dữ liệu và các lớp của nó. Nó bắt đầu như một mô hình đơn giản mà không phải đối phó với các khía cạnh thời gian:
1 Kịch bản: Không Temporal Mẫu
Data Model:
Đội:
@Entity
public class Team implements Serializable {
private Long id;
private String name;
private Integer wins = 0;
private Integer losses = 0;
private Integer draws = 0;
private List<Player> players = new ArrayList<Player>();
public Team() {
}
public Team(String name) {
this.name = name;
}
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQTEAMID")
@SequenceGenerator(name="SEQTEAMID", sequenceName="SEQTEAMID", allocationSize=1)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(unique=true, nullable=false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getWins() {
return wins;
}
public void setWins(Integer wins) {
this.wins = wins;
}
public Integer getLosses() {
return losses;
}
public void setLosses(Integer losses) {
this.losses = losses;
}
public Integer getDraws() {
return draws;
}
public void setDraws(Integer draws) {
this.draws = draws;
}
@OneToMany(mappedBy="team", cascade=CascadeType.ALL)
public List<Player> getPlayers() {
return players;
}
public void setPlayers(List<Player> players) {
this.players = players;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Team other = (Team) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
Máy nghe nhạc:
@Entity
@Table(uniqueConstraints={@UniqueConstraint(columnNames={"team_id","number"})})
public class Player implements Serializable {
private Long id;
private Team team;
private Integer number;
private String name;
public Player() {
}
public Player(Team team, Integer number) {
this.team = team;
this.number = number;
}
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQPLAYERID")
@SequenceGenerator(name="SEQPLAYERID", sequenceName="SEQPLAYERID", allocationSize=1)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne
@JoinColumn(nullable=false)
public Team getTeam() {
return team;
}
public void setTeam(Team team) {
this.team = team;
}
@Column(nullable=false)
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
@Column(unique=true, nullable=false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((number == null) ? 0 : number.hashCode());
result = prime * result + ((team == null) ? 0 : team.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Player other = (Player) obj;
if (number == null) {
if (other.number != null)
return false;
} else if (!number.equals(other.number))
return false;
if (team == null) {
if (other.team != null)
return false;
} else if (!team.equals(other.team))
return false;
return true;
}
}
Kiểm tra lớp:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/META-INF/application-context-root.xml"})
@Transactional
public class TestingDao {
@PersistenceContext
private EntityManager entityManager;
private Team team;
@Before
public void setUp() {
team = new Team();
team.setName("The Goods");
team.setLosses(0);
team.setWins(0);
team.setDraws(0);
Player player = new Player();
player.setTeam(team);
player.setNumber(1);
player.setName("Alfredo");
team.getPlayers().add(player);
player = new Player();
player.setTeam(team);
player.setNumber(2);
player.setName("Jorge");
team.getPlayers().add(player);
entityManager.persist(team);
entityManager.flush();
}
@Test
public void testPersistence() {
String strQuery = "select t from Team t where t.name = :name";
TypedQuery<Team> query = entityManager.createQuery(strQuery, Team.class);
query.setParameter("name", team.getName());
Team persistedTeam = query.getSingleResult();
assertEquals(2, persistedTeam.getPlayers().size());
//Change the player number
Player p = null;
for (Player player : persistedTeam.getPlayers()) {
if (player.getName().equals("Alfredo")) {
p = player;
break;
}
}
p.setNumber(10);
}
}
Bây giờ bạn sẽ được yêu cầu giữ một lịch sử của cách đội và cầu thủ đang trên thời điểm nhất định vì vậy những gì bạn cần làm là thêm một khoảng thời gian cho mỗi bảng muốn được theo dõi. Vì vậy, hãy thêm các cột thời gian này. Chúng ta sẽ bắt đầu chỉ với Player
.
2 Kịch bản: Temporal Mẫu
Data Model:
Như bạn có thể thấy chúng tôi đã phải thả các khóa chính và xác định một số khác bao gồm các ngày (thời gian). Ngoài ra, chúng tôi đã phải loại bỏ các ràng buộc duy nhất bởi vì bây giờ chúng có thể được lặp lại trong bảng. Bây giờ bảng có thể chứa các mục hiện tại và cũng là lịch sử.
Mọi thứ trở nên xấu xí nếu chúng ta phải tạo Đội thời gian, trong trường hợp này chúng ta sẽ cần phải giảm ràng buộc khóa ngoài mà bảng Player
phải là Team
. Vấn đề là làm thế nào bạn sẽ mô hình hóa đó trong Java và JPA.
Lưu ý rằng ID là khóa thay thế. Nhưng bây giờ các khóa thay thế phải bao gồm ngày bởi vì nếu họ không nó sẽ không cho phép lưu trữ nhiều hơn một "phiên bản" của cùng một thực thể (trong dòng thời gian).
1) bạn đã vẽ sơ đồ công cụ nào? 2) một chiều thời gian là đủ cho yêu cầu của bạn, các mẫu DAOFusion và cũng là câu trả lời của tôi (dựa trên các mẫu này) là quá mức trong quan điểm của tôi 3) Bạn có thích một giải pháp chỉ bổ sung khía cạnh thời gian cho Trình phát hay bạn thích nó cho cả hai bảng 4) đoạn cuối cùng của bạn là sai. Khóa thay thế sẽ không bao giờ bao gồm các trường bổ sung. Trong trường hợp đó, bạn sẽ có hai khóa thay thế. – ChrLipp
@ChrLipp 1) Sparx Enterprise Architect 2) Tôi đồng ý. 3) Tôi cần một giải pháp cho biết thêm thời gian cho cả hai bảng. 4) Tôi không đồng ý rằng đó không phải là chìa khóa thay thế. Tôi nghĩ rằng đó là một chìa khóa thay thế bởi vì: 1. Trước khi thêm cột thời gian nó là một chìa khóa thay thế đó là một chìa khóa không có ý nghĩa kinh doanh.Ví dụ, khóa kinh doanh của Player là "team_id" và "number" và từ Team là "name". Cả hai đều có khóa thay thế của họ "id" khi họ không có cột thời gian. Vấn đề là khi tôi thêm các cột thời gian không hoạt động nữa. Mục nhập tương tự có thể xuất hiện nhiều lần trong cùng một bảng. –
Đó là lý do tại sao khóa thay thế "id" của chính nó không thể chỉ là một cột nữa vì nó là cùng một mục nhưng được theo dõi trong các mốc thời gian khác nhau, vì vậy để cho phép cùng một mục xuất hiện nhiều hơn một lần tôi có thể đã thêm sau đây là khóa chính "id + validstart" hoặc "id + validend" hoặc "id + validstart + validend". Tôi đã chọn tùy chọn cuối cùng để thuận tiện trên Ánh xạ Java, nơi tôi có đối tượng "Khoảng thời gian" định nghĩa một khoảng thời gian, vì vậy để ánh xạ trong JPA, tôi đã thêm "Khoảng thời gian" vào Id dưới dạng EmbeddedId. –