JPA - @ElementCollection с дополнительными атрибутами - PullRequest
1 голос
/ 29 марта 2020

1. Проблема

Я знаю, что @ElementCollection автоматически создает таблицу, в которой взаимосвязи обрабатываются. Однако можно ли добавить дополнительные атрибуты в такую ​​автоматически созданную таблицу?

2. Пример

У меня есть сущность (класс) "Вызов", в которой есть участники поля:

@ElementCollection
private List<Long> participants = new ArrayList<>();

Результат следующий в базе данных:

challenge (several attributes, ...)
challenge_participants(challenge_id, some_long_value_of_the_list)

Как бы я теперь добавил другое поле к challenge_participants? Например, отметка времени, когда этот участник принял участие в соревновании. Тогда это будет выглядеть так:

challenge_participants(challenge_id, some_long_value_of_the_list, enter_timestamp)

3. Вопрос

Есть идеи, как это можно реализовать в JPA?

Обновление

Я решил эту проблему, создав класс @Embeddable с соответствующими полями, используя его как тип для списка:

@Embeddable
public class Participant { ... }

Класс сущности теперь выглядит следующим образом:

@ElementCollection
private List<Participant> participants = new ArrayList<>();

Надеюсь, это поможет кому-то в будущем.

1 Ответ

1 голос
/ 29 марта 2020

AFAIK невозможно с @ElementCollection. Кроме того, у вас, похоже, и здесь совершенно другая ситуация.

Основываясь на своем описании, вы можете сказать, что имеете дело с двумя сильными сущностями плюс отношение Многие ко многим между ними. вот так:

         <a href="https://i.stack.imgur.com/jbkSX.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/jbkSX.png" alt="enter image description here"></a>

Итак, это означает, что вам нужна дополнительная таблица Participation для поддержания отношения Many-to-Many между сущностью Participant и Challenge. Хорошо, если у вас есть репрезентативный класс этого отношения, например Participation, вы можете добавить к нему столько дополнительной информации, сколько вам нужно. Обратите внимание, что отношение Participation определяется составным первичным ключом, который состоит из PK как сущностей Participant, так и Challenge.

Проверьте этот учебник, где вы найдете подробную информацию о том, как работа, а также информация о различных сценариях ios относительно реализации: https://www.baeldung.com/jpa-many-to-many

Вот пример, который я создал очень быстро. Не проверенный код, но в основном то, что я имел в виду выше, выглядит следующим образом:

@Entity
class Participant {
  @OneToMany(mappedBy = "participant")
  private Set<Participation> participations;

  // other fields, getters & setters...
}

@Entity
class Challenge {
  @OneToMany(mappedBy = "challenge")
  private Set<Participation> participations;

  // other fields, getters & setters...
}


@Embeddable
class ParticipationKey implements Serializable {
  @Column(name = "participant_id")
  private Long participantId;

  @Column(name = "challenge_id")
  private Long challengeId;

  // getters & setters...
}


@Entity
class Participation {
  @EmbeddedId
  private ParticipationKey id;

  @ManyToOne
  @MapsId("participantId") // targets the ParticipationKey.participantId
  @JoinColumn(name = "participant_id")
  private Participant participant;

  @ManyToOne
  @MapsId("challengeId") // targets the ParticipationKey.challengeId
  @JoinColumn(name = "challenge_id")
  private Challenge challenge;

  @CreationTimestamp
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name = "date_created")
  private Date createDate;

  @UpdateTimestamp
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name = "date_modified")
  private Date modifyDate;

  // other fields, getters & setters...
}

Обновление

Возможно, вы знаете, как лучше всего вставить данные в этот вид отношение?

К сожалению, я не совсем уверен, какой «лучший» способ сделать это будет с JPA, поскольку я никогда не реализовывал такого рода отношения «многие ко многим» (с дополнительными полями). с JPA раньше. Посмотрите на фрагмент рабочего кода ниже. Важно то, что вы сначала используете persist для сохранения Participant и Challenge сущностей, чтобы получить PK для каждого, затем вы можете просто создать Participation s, где вы должны использовать merge (em.merge(...)) для экземпляров Participation при сохранении в базу данных.

Я также загрузил полностью рабочий пример на GitHub: https://gist.github.com/kenangueler/c69b05c90928dd2f5d2fe4615f60faf4

Примечание: Spring Boot используется, но это почти то же самое с JEE.

// create and persist participants
Participant participant1 = new Participant("Kenan Gueler");
Participant participant2 = new Participant("Elon Musk");
participantRepository.save(participant1); // entityManager.persist()
participantRepository.save(participant2); // entityManager.persist()

// create and persist challenges
Challenge challenge1 = new Challenge("Coding challenge");
Challenge challenge2 = new Challenge("Hot pepper challenge");
challengeRepository.save(challenge1); // entityManager.persist()
challengeRepository.save(challenge2); // entityManager.persist()

// create and persists challenge1 participations
Participation participation1_1 = new Participation(participant1, challenge1, "This guy knows nothing. He failed.");
Participation participation1_2 = new Participation(participant2, challenge1, "This guy did great!");
participationRepository.save(participation1_1); // entityManager.merge()
participationRepository.save(participation1_2);  // entityManager.merge()

// create and persists challenge2 participations
Participation participation2_1 = new Participation(participant1, challenge2, "Solid steel");
Participation participation2_2 = new Participation(participant2, challenge2, "Crying...");
participationRepository.save(participation2_1); // entityManager.merge()
participationRepository.save(participation2_2); // entityManager.merge()

Таблицы

challenge

enter image description here

participant

enter image description here

participation

enter image description here

...