Есть сущность класса «А». У класса A могут быть дети того же типа «A». Также "A" должен содержать его родителя, если это ребенок.
Это возможно? Если да, то как мне сопоставить отношения в классе Entity? [«A» имеет столбец идентификаторов.]
Да, это возможно. Это особый случай стандартного двунаправленного @ManyToOne
/ @OneToMany
отношений. Он особенный, потому что объекты на каждом конце отношения одинаковы. Общий случай подробно описан в разделе 2.10.2 спецификации JPA 2.0. .
Вот наработанный пример. Во-первых, класс сущности A
:
@Entity
public class A implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private A parent;
@OneToMany(mappedBy="parent")
private Collection<A> children;
// Getters, Setters, serialVersionUID, etc...
}
Вот примерный main()
метод, который сохраняет три таких объекта:
public static void main(String[] args) {
EntityManager em = ... // from EntityManagerFactory, injection, etc.
em.getTransaction().begin();
A parent = new A();
A son = new A();
A daughter = new A();
son.setParent(parent);
daughter.setParent(parent);
parent.setChildren(Arrays.asList(son, daughter));
em.persist(parent);
em.persist(son);
em.persist(daughter);
em.getTransaction().commit();
}
В этом случае все три экземпляра сущности должны быть сохранены до фиксации транзакции. Если мне не удается сохранить одну из сущностей на графе родительско-дочерних отношений, возникает исключение commit()
. В Eclipselink это RollbackException
подробное описание несоответствия.
Такое поведение настраивается с помощью cascade
атрибута A
«с @OneToMany
и @ManyToOne
аннотаций. Например, если я использую cascade=CascadeType.ALL
обе эти аннотации, я могу безопасно сохранить одну из сущностей и игнорировать другие. Скажем, я настаивал parent
на своей транзакции. Траверсы реализации JPA parent
«ы children
собственности , потому что он отмечен CascadeType.ALL
. Реализация JPA находит son
и daughter
там. Затем он сохраняет обоих детей от моего имени, хотя я явно не запрашивал это.
Еще одно замечание. Ответственность за обновление обеих сторон двунаправленной связи всегда лежит на программисте. Другими словами, всякий раз, когда я добавляю дочернего элемента к какому-либо родительскому элементу, я должен соответствующим образом обновить его родительское свойство. Обновление только одной стороны двунаправленной связи является ошибкой в JPA. Всегда обновляйте обе стороны отношений. Это недвусмысленно написано на странице 42 спецификации JPA 2.0:
Обратите внимание, что именно приложение несет ответственность за поддержание согласованности взаимосвязей во время выполнения - например, за обеспечение того, чтобы «одна» и «многие» стороны двунаправленной взаимосвязи согласовывались друг с другом, когда приложение обновляет взаимосвязь во время выполнения. .
Для меня уловка заключалась в использовании отношения «многие ко многим». Предположим, что ваш объект A - это подразделение, которое может иметь подразделения. Затем (пропуская нерелевантные подробности):
Поскольку у меня была обширная бизнес-логика вокруг иерархической структуры, а JPA (на основе реляционной модели) очень слаб для ее поддержки, я представил интерфейс
IHierarchyElement
и прослушиватель сущностейHierarchyListener
:источник
Top
связь. Страница 93 спецификации JPA 2.0, Слушатели сущностей и методы обратного вызова: «В общем, метод жизненного цикла переносимого приложения не должен вызывать операции EntityManager или Query, обращаться к другим экземплярам сущностей или изменять отношения». Правильно? Дай мне знать, если я уйду.