Яка різниця між односпрямованими та двонаправленими асоціаціями JPA та сплячого режиму?


135

Чим відрізняються односпрямовані та двонаправлені асоціації?

Оскільки таблиця, що генерується в db, однакова, тому я знайшов єдину різницю в тому, що кожна сторона двонаправлених асоціацій матиме посилання на іншу, а односпрямована - ні.

Це односпрямоване об’єднання

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;
}

Двонаправлена ​​асоціація

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;
}

Різниця полягає в тому, чи група має посилання користувача.

Тож мені цікаво, чи це єдина різниця? що рекомендується?


7
Група тепер дізнається, яких користувачів вона містить. Я не думаю, що це в будь-якій мірі невелика різниця.
Сатадру Бісвас

5
Двосторонні стосунки стали для мене хаосом, коли справа стосується оновлення. :)
diyoda_

Відповіді:


152

Основна різниця полягає в тому, що двонаправлені відносини забезпечують навігаційний доступ в обох напрямках, так що ви можете отримати доступ до іншої сторони без явних запитів. Також це дозволяє застосовувати каскадні варіанти в обох напрямках.

Зауважте, що навігаційний доступ не завжди хороший, особливо для відносин «один-дуже-багато-багато» та «багато-до-дуже-багатьох». Уявіть собі, Groupщо містить тисячі Users:

  • Як би ви отримали доступ до них? З такою кількістю Users зазвичай вам потрібно застосувати деяку фільтрацію та / або пагінацію, так що вам все одно потрібно виконати запит (якщо ви не використовуєте фільтрацію колекції , яка для мене схожа на злом). Деякі розробники, як правило, застосовують фільтрацію в пам'яті в таких випадках, що, очевидно, не добре для продуктивності. Зауважте, що такі відносини можуть спонукати таких розробників використовувати його, не враховуючи наслідків для продуктивності.

  • Як би ви додали нові Users до Group? До щастя, Hibernate дивиться на володіє боку відносин , коли зберігається його, так що ви можете встановити тільки User.group. Тим НЕ менше, якщо ви хочете зберегти об'єкти в пам'яті послідовно, також необхідно додати Userдо Group.users. Але це зробило б сплячку отримати всі елементи Group.usersз бази даних!

Отже, я не можу погодитися з рекомендацією Best Practices . Вам потрібно ретельно розробити двонаправлені відносини, враховуючи випадки використання (чи потрібен вам навігаційний доступ в обох напрямках?) Та можливі наслідки для продуктивності.

Дивитися також:


Привіт, спасибі, здається, що ви фахівець сплячого режиму, оскільки ви відповіли на моє запитання: stackoverflow.com/questions/5350770/… . І тепер я не впевнений , що відносини холдингу, так як я не можу більше писати в коментарях, тому я його тут dpaste.de/J85m .Please мати чек , якщо це можливо :).
hguser

@hguser: Якщо ви , нарешті , вирішили зробити вас відносини двонаправленим, я думаю , було б краще , щоб виклик setGroup()від addUser()того , щоб тримати обидві сторони послідовні.
axtavt

як щодо того, якщо я не викликаю setGroup () всередині group.addUser ()?
hguser

@hguser: Відносини не зберігатимуться, див. у відповіді пункт 2. Можна дзвонити setGroup()без addUser(), але це призведе до непослідовного стану об'єктів у пам'яті.
октавт

Я виявив, що я не можу зробити правильне відображення. Ви можете витратити трохи часу, щоб перевірити мій проект у github? це невеликий проект.
hguser

31

Є дві основні відмінності.

Доступ до сторін асоціації

Перший стосується того, як ви отримаєте доступ до відносин. Для однонаправленої асоціації ви можете переміщатися по асоціації лише з одного кінця.

Отже, для односпрямованого @ManyToOneоб'єднання це означає, що ви можете отримати доступ до відносин лише з боку дитини, де знаходиться іноземний ключ.

Якщо у вас є однонаправлена @OneToManyасоціація, це означає, що ви можете отримати доступ до відносин лише з батьківської сторони, де знаходиться зовнішній ключ.

Для двонаправленої @OneToManyасоціації ви можете орієнтуватися на асоціацію обома способами - або з батьківського, або з дочірнього боку.

Також потрібно використовувати методи додавання / видалення утиліти для двонаправлених асоціацій, щоб переконатися в правильності синхронізації обох сторін .

Продуктивність

Другий аспект пов'язаний з продуктивністю.

  1. Для @OneToMany, односпрямовані об'єднання не виконують, а також двонапрямлених з них .
  2. Так @OneToOne, двонаправлена ​​асоціація призведе до того, що батьків буде нетерпляче отримати, якщо сплячий не зможе сказати, чи повинен бути призначений проксі або нульове значення .
  3. Для @ManyToMany, типу колекції робить досить різниця , як Setsкраще , ніжLists .

11

Що стосується кодування, двосторонній взаємозв'язок є складнішим для реалізації, оскільки програма відповідає за підтримку обох сторін синхронно згідно зі специфікацією 5 JPA (на сторінці 42). На жаль, приклад, наведений у специфікації, не дає більше деталей, тому не дає уявлення про рівень складності.

Якщо не використовується кеш другого рівня, зазвичай не є правильним застосуванням методів зв’язків, оскільки екземпляри відкидаються в кінці транзакції.

Якщо використовується кеш другого рівня, якщо щось пошкоджується через неправильно реалізовані методи обробки відносин, це означає, що інші транзакції також побачать пошкоджені елементи (кеш другого рівня є глобальним).

Правильно реалізовані двонаправлені відносини можуть спрощувати запити та код, але їх не слід використовувати, якщо це насправді не має сенсу з точки зору ділової логіки.


9

Я не на 100% впевнений, що це єдина різниця, але це головна відмінність. Рекомендується також мати двонаправлені асоціації зі сплячих документів:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

Конкретно:

Віддайте перевагу двонаправленим асоціаціям: Односпрямовані асоціації складніше запитувати. У великому застосуванні майже всі асоціації повинні знаходитись в обох напрямках у запитах.

У мене особисто є невелика проблема з цією рекомендацією, що стосується ковдри - мені здається, є випадки, коли дитина не має жодних практичних причин знати про свого батька (наприклад, чому товар замовлення повинен знати про замовлення, яким воно є асоціюється з?), але я вважаю цінністю в цьому і розумну частину часу. А оскільки двонаправленість насправді нічого не шкодить, я не вважаю це занадто несприятливим для дотримання.


Двонаправленість може зашкодити в деяких випадках, як пояснив axtavt! Я був би дуже обережний із кожним відношенням, відображеним у сплячому режимі! Ви можете закінчити нескінченний час, необхідний для завантаження речей у сплячому режимі, якщо ви точно не знаєте, що робите. Ретельно продумайте випадки використання та використовуйте різні класи моделей для різних випадків використання. F.ex. У списку речей мені не потрібні всі пов’язані об’єкти, лише мітка та ідентифікатор. Тож сутність списку для мене є іншою (і дуже простою), ніж сутність деталей.
cslotty
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.