Istnieje klasa jednostek „A”. Klasa A może mieć elementy podrzędne tego samego typu „A”. Również „A” powinno trzymać swojego rodzica, jeśli jest dzieckiem.
czy to możliwe? Jeśli tak, jak mam odwzorować relacje w klasie Entity? [„A” ma kolumnę id.]
Tak, jest to możliwe. Jest to szczególny przypadek standardowego dwukierunkowego @ManyToOne
/ @OneToMany
relacji. Jest wyjątkowy, ponieważ jednostka na każdym końcu związku jest taka sama. Ogólny przypadek opisano szczegółowo w sekcji 2.10.2 specyfikacji JPA 2.0 .
Oto praktyczny przykład. Po pierwsze, klasa encji 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...
}
Oto przybliżona main()
metoda, która utrzymuje trzy takie jednostki:
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();
}
W takim przypadku wszystkie trzy instancje jednostki muszą zostać utrwalone przed zatwierdzeniem transakcji. Jeśli nie uda mi się utrwalić jednej z encji na wykresie relacji rodzic-dziecko, zostanie zgłoszony wyjątek commit()
. W Eclipselink jest to RollbackException
wyszczególnienie niespójności.
Takie zachowanie jest konfigurowany przez cascade
atrybutu A
„s @OneToMany
i @ManyToOne
adnotacji. Na przykład, jeśli ustawię cascade=CascadeType.ALL
obie te adnotacje, mogę bezpiecznie utrwalić jedną z jednostek i zignorować pozostałe. Powiedz, że wytrwałam parent
w transakcji. Implementacja JPA przechodzi parent
przez children
właściwość, ponieważ jest oznaczona znakiem CascadeType.ALL
. Wdrożenie JPA znajduje son
i daughter
tam. Następnie oboje dzieci utrzymują się w moim imieniu, mimo że wyraźnie o to nie prosiłem.
Jeszcze jedna uwaga. Obowiązkiem programisty jest zawsze aktualizacja obu stron relacji dwukierunkowej. Innymi słowy, ilekroć dodaję dziecko do jakiegoś rodzica, muszę odpowiednio zaktualizować jego własność rodzicielską. Aktualizowanie tylko jednej strony relacji dwukierunkowej jest błędem w JPA. Zawsze aktualizuj obie strony relacji. Jest to jednoznacznie napisane na stronie 42 specyfikacji JPA 2.0:
Należy zauważyć, że to aplikacja ponosi odpowiedzialność za utrzymanie spójności relacji w czasie wykonywania - na przykład za zapewnienie, że „jedna” i „wiele” stron relacji dwukierunkowej są ze sobą spójne, gdy aplikacja aktualizuje relację w czasie wykonywania .
Dla mnie sztuczka polegała na wykorzystaniu relacji wiele do wielu. Załóżmy, że Twój byt A jest dywizją, która może mieć podpodziały. Następnie (pomijając nieistotne szczegóły):
Ponieważ miałem rozbudowaną logikę biznesową dotyczącą struktury hierarchicznej, a JPA (oparty na modelu relacyjnym) jest bardzo słaba, aby ją wspierać, wprowadziłem interfejs
IHierarchyElement
i odbiornik encjiHierarchyListener
:źródło
Top
jest to relacja. Strona 93 specyfikacji JPA 2.0, Entity Listeners i Callback Methods: „Ogólnie rzecz biorąc, metoda cyklu życia aplikacji przenośnej nie powinna wywoływać operacji EntityManager ani Query, uzyskiwać dostępu do innych instancji encji ani modyfikować relacji”. Dobrze? Daj mi znać, jeśli wyjdę.