Как реализовать временную таблицу с использованием JPA?

Я хотел бы знать, как реализоватьвременные таблицы в JPA 2 с EclipseLink. Под временными я подразумеваю таблицы, которые определяют срок действия.

Одна проблема, с которой я сталкиваюсь, состоит в том, что у ссылочных таблиц больше не может быть ограничений внешних ключей для ссылочных таблиц (временных таблиц) из-за природы ссылочных таблиц, которые теперь их первичные ключи включают в себя период действия.

Как бы я отобразил отношения моих сущностей?Означает ли это, что мои сущности больше не могут иметь отношения с этими действительными сущностями?Должна ли ответственность за инициализацию этих отношений в настоящее время выполнять я вручную в какой-либо службе или специализированном DAO?

Единственное, что я нашел, это фреймворкДАО Фьюжн который имеет дело с этим.

Есть ли другие способы решить эту проблему?Не могли бы вы привести пример или ресурсы по этой теме (JPA с временными базами данных)?

Вот вымышленный пример модели данных и ее классов. Все начинается с простой модели, которая не должна иметь дело с временными аспектами:

1-й сценарий: не временная модель

Модель данных:

команда:

@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;
    }


}

игрок:

@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;
    }


}

Тестовый класс:

@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);        
    }


}

Теперь вас просят вести историю о том, как команда и игрок находились в определенный момент времени, поэтому вам нужно добавить период времени для каждой таблицы, которую вы хотите отслеживать. Итак, давайте добавим эти временные столбцы. Мы собираемся начать с простоPlayer.

2-й сценарий: временная модель

Модель данных:

Как видите, нам пришлось отбросить первичный ключ и определить другой, который включает в себя даты (период). Также нам пришлось отбросить уникальные ограничения, потому что теперь они могут повторяться в таблице. Теперь таблица может содержать текущие записи, а также историю.

Все становится довольно уродливым, если мы также сделаем команду временной, в этом случае нам нужно будет снять ограничение внешнего ключа,Player стол долженTeam, Проблема в том, как бы вы смоделировали это в Java и JPA.

Обратите внимание, что ID является суррогатным ключом. Но теперь суррогатные ключи должны включать дату, потому что если они этого не сделают, это не позволит сохранить более одного "версия«одного и того же лица (в течение срока).

Ответы на вопрос(4)

Ваш ответ на вопрос