Привет, у меня следующие отношения:
@Entity
public class Athlete implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer athleteId;
@ManyToOne
@JoinColumn(name = "closetWaiting")
private Closet closetWaiting;
....
@Entity
public class Closet implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer closetId;
@OneToMany(mappedBy = "closetWaiting")
private List<Athlete> waitingList;
....
и в моем классе Bean у меня есть этот код:
public void addAthleteIntoWaitingList(String closetId, Athlete singleAthlete ) {
Closet singleCloset=entityManager.find(Closet.class,Integer.parseInt(closetId));
List<Athlete> waitingList=singleCloset.getWaitingList();
waitingList.add(singleAthlete);
singleCloset.setWaitingList(waitingList);
singleAthlete.setClosetWaiting(singleCloset);
}
который не работает, так как после того, как я вызываю метод addAthleteIntoWaitingList, столбец CLOSETWAITING в таблице Athlete всегда равен нулю.
Я делаю что-то не так здесь? Любое предложение для решения?
Обновлено:
Чтобы понять, что происходит за кодом, я активировал свойства регистрации eclipse в файле persistence.xml. Итак, вот что я получаю, когда вызываю метод:
2019-03-26T10:37:16.862+0100|Fein: SELECT ATHLETEID, FIRSTNAME, GENDER, LASTNAME, PHONENUMBER, closetWaiting FROM ATHLETE WHERE (ATHLETEID = ?)
bind => [12]
2019-03-26T10:37:16.871+0100|Fein: SELECT CLOSETID, CLOSETRANK, GENDER, ISBROKEN, ISOCCUPIED, RESERVATIONENDED, RESERVATIONSTARTED, athleteId FROM CLOSET WHERE (CLOSETID = ?)
bind => [5]
2019-03-26T10:37:16.876+0100|Fein: SELECT CLOSETID, CLOSETRANK, GENDER, ISBROKEN, ISOCCUPIED, RESERVATIONENDED, RESERVATIONSTARTED, athleteId FROM CLOSET
Это означает, что JPA получает Athlete с Id=12, а затем находит шкаф с Id=5. Но затем он полностью игнорирует остальную часть кода, где спортсмен добавляется в список ожидания, и не сохраняет его в базе данных.
Покажите теперь реальный вопрос, почему это происходит?
РЕШЕНИЕ:
За исключением решения @Peter, которое отлично сработало, я внес следующие изменения без добавления какого-либо каскадного типа и, что более важно, без вызова метода слияния:
Я изменил способ, которым мой метод получает объект Athlete. Вместо того, чтобы передавать его в качестве параметра, я получаю его через EntityManager.find() внутри моего EJB Bean. Вот как это выглядит:
public void addAthleteIntoWaitingList(String closetId, String athleteId ) {
Closet singleCloset=entityManager.find(Closet.class, Integer.parseInt(closetId));
Athlete singleAthlete=entityManager.find(Athlete.class, Integer.parseInt(athleteId));
List<Athlete> waitingList=singleCloset.getWaitingList();
waitingList.add(singleAthlete);
singleCloset.setWaitingList(waitingList);
singleAthlete.setClosetWaiting(singleCloset);
}
Может ли кто-нибудь объяснить мне, почему это сработало? Я думаю, потому что я манипулирую объектом Ahtlete внутри транзакции или нет?
Класс бобов? Используете ли вы транзакции EJB или как сохраняется шкаф? Откуда вызывается метод?
@PeterŠály Я вызываю метод addAthleteIntoWaitingList из EJB-компонента LocalBean без сохранения состояния.
Вы уже вызываете слияние (туалет)?





Без @OneToMany(cascade=CascadeType.ALL) коллекция не будет сохранена при сохранении родительского объекта.
Если вы изменяете свойство объекта в транзакции, нет необходимости явно вызывать слияние. Если объект выходит за пределы транзакции, он становится DETACHED. Отдельная сущность — это singleAthlete. Слияние необходимо. Транзакция автоматически фиксируется контейнером, выходящим из последнего метода EJB.
Явно вызовите entityManager.merge(closet).
Эй, спасибо за предложение, но это не работает для меня. В то время, когда я добавляю объект singleAthlete, он уже существует. Таким образом, этот каскадный тип вызывает исключение, связанное с нарушением первичного ключа, потому что JPA пытается вставить этот объект еще раз.
Явно вызовите entityManager.merge(closet) с приведенным выше каскадированием
Эй, Питер, это сработало. Большое спасибо. Хотя я до сих пор не понимаю, что происходит с контекстом JPA. Я думал, что каждое изменение, внесенное в свойство, сохраняется без явного вызова любого метода обновления или слияния, не так ли?
Подробнее о жизненном цикле объекта см. здесь dzone.com/articles/jpa-entity-lifecycle.
Я думаю, прежде чем добавлять "singleAthlete" в список, вы должны сохранить его в базе данных, поэтому перед waitList.add(singleAthlete) попробуйте: entityManager.persist(один спортсмен); Конечно, не забудьте объединить singleCloset и зафиксировать результаты: так что вы, наконец, вызываете: entityManager.merge (один шкаф); entityManager.getTransaction().commit();
Вероятно, вы не запустили этот код внутри транзакции или забыли зафиксировать транзакцию. Код, который вы разместили, можно было бы улучшить, но он правильный.