Jaka jest różnica między asocjacjami jednokierunkowymi i dwukierunkowymi?
Ponieważ wszystkie tabele wygenerowane w bazie danych są takie same, jedyną różnicą, jaką znalazłem, jest to, że każda strona dwukierunkowych powiązań będzie miała odniesienie do drugiej, a jednokierunkowa nie.
To jest skojarzenie jednokierunkowe
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
}
Skojarzenie dwukierunkowe
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
@OneToMany(mappedBy="group")
private List<User> users;
}
Różnica polega na tym, czy grupa posiada referencję użytkownika.
Więc zastanawiam się, czy to jedyna różnica? co jest zalecane?
Odpowiedzi:
Główną różnicą jest to, że relacja dwukierunkowa zapewnia dostęp nawigacyjny w obu kierunkach, dzięki czemu można uzyskać dostęp do drugiej strony bez wyraźnych zapytań. Pozwala również na zastosowanie opcji kaskadowych w obu kierunkach.
Należy zauważyć, że dostęp nawigacyjny nie zawsze jest dobry, szczególnie w przypadku relacji „jeden do bardzo wielu” i „wiele do bardzo wielu”. Wyobraź sobie,
Group
że zawiera tysiąceUser
s:Jak masz do nich dostęp? Przy tak wielu
User
sach zwykle trzeba zastosować filtrowanie i / lub paginację, tak że i tak trzeba wykonać zapytanie (chyba że używasz filtrowania kolekcji , co dla mnie wygląda na hack). Niektórzy programiści mogą mieć w takich przypadkach tendencję do stosowania filtrowania w pamięci, co oczywiście nie jest dobre dla wydajności. Zauważ, że posiadanie takiej relacji może zachęcić programistów tego rodzaju do korzystania z niej bez uwzględnienia wpływu na wydajność.Jak dodasz nowe
User
s doGroup
? Na szczęście Hibernate patrzy na stronę właściciela relacji, gdy ją utrzymuje, więc możesz tylko ustawićUser.group
. Jednakże, jeśli chcesz zachować obiekty w pamięci spójne, trzeba także dodaćUser
doGroup.users
. Ale to spowodowałoby, że Hibernate mógłby pobrać wszystkie elementyGroup.users
z bazy danych!Dlatego nie mogę zgodzić się z zaleceniem zawartym w Najlepszych praktykach . Musisz starannie zaprojektować relacje dwukierunkowe, biorąc pod uwagę przypadki użycia (czy potrzebujesz dostępu nawigacyjnego w obu kierunkach?) I możliwe konsekwencje dla wydajności.
Zobacz też:
źródło
setGroup()
zaddUser()
, aby zachować spójność obu stron.setGroup()
bezaddUser()
, ale spowodowałoby to niespójny stan obiektów w pamięci.Istnieją dwie główne różnice.
Dostęp do stron stowarzyszenia
Pierwsza dotyczy tego, w jaki sposób uzyskasz dostęp do związku. W przypadku asocjacji jednokierunkowej możesz nawigować po asocjacji tylko z jednego końca.
Tak więc w przypadku
@ManyToOne
skojarzenia jednokierunkowego oznacza to, że dostęp do relacji można uzyskać tylko od strony podrzędnej, w której znajduje się klucz obcy.Jeśli masz
@OneToMany
skojarzenie jednokierunkowe , oznacza to, że możesz uzyskać dostęp do relacji tylko od strony nadrzędnej, gdzie znajduje się klucz obcy.W przypadku
@OneToMany
asocjacji dwukierunkowej możesz nawigować po asocjacji na oba sposoby, od strony rodzica lub strony podrzędnej.Należy również użyć metod narzędzi dodawania / usuwania dla skojarzeń dwukierunkowych, aby upewnić się, że obie strony są prawidłowo zsynchronizowane .
Występ
Drugi aspekt dotyczy wydajności.
@OneToMany
, jednokierunkowe stowarzyszenia nie wykonują, jak również te, które dwukierunkowych .@OneToOne
, dwukierunkowe powiązanie spowoduje, że rodzic będzie chętnie pobierany, jeśli Hibernate nie może określić, czy należy przypisać serwer proxy, czy wartość zerową .@ManyToMany
, typ kolekcji sprawia, że dość różnica jakSets
wykonać lepiej niżLists
.źródło
Pod względem kodowania relacja dwukierunkowa jest bardziej złożona do wdrożenia, ponieważ aplikacja jest odpowiedzialna za utrzymywanie synchronizacji obu stron zgodnie ze specyfikacją JPA 5 (na stronie 42). Niestety przykład podany w specyfikacji nie podaje więcej szczegółów, więc nie daje wyobrażenia o poziomie złożoności.
Jeśli nie używasz pamięci podręcznej drugiego poziomu, zazwyczaj nie jest problemem, jeśli metody relacji są poprawnie zaimplementowane, ponieważ instancje są odrzucane na koniec transakcji.
Podczas korzystania z pamięci podręcznej drugiego poziomu, jeśli cokolwiek zostanie uszkodzone z powodu nieprawidłowo zaimplementowanych metod obsługi relacji, oznacza to, że inne transakcje również będą widzieć uszkodzone elementy (pamięć podręczna drugiego poziomu jest globalna).
Prawidłowo zaimplementowana relacja dwukierunkowa może uprościć zapytania i kod, ale nie należy jej używać, jeśli nie ma to sensu z punktu widzenia logiki biznesowej.
źródło
Nie jestem w 100% pewien, że to jedyna różnica, ale to główna różnica. Zaleca się również, aby asocjacje dwukierunkowe były opisane w dokumentacji Hibernate:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html
Konkretnie:
Osobiście mam mały problem z tą ogólną rekomendacją - wydaje mi się, że są przypadki, w których dziecko nie ma żadnego praktycznego powodu, aby wiedzieć o swoim rodzicu (np. Dlaczego pozycja zamówienia musi wiedzieć o kolejności, w jakiej jest związane z?), ale widzę w tym wartość również w rozsądnej części czasu. A ponieważ dwukierunkowość tak naprawdę niczego nie szkodzi, nie uważam, aby jej przestrzeganie było zbyt niepożądane.
źródło