В чем разница между однонаправленными и двунаправленными ассоциациями JPA и Hibernate? - PullRequest
118 голосов
/ 19 марта 2011

В чем разница между однонаправленными и двунаправленными ассоциациями?

Поскольку все таблицы, сгенерированные в БД, одинаковы, единственное различие, которое я обнаружил, заключается в том, что каждая сторона двунаправленных ассоциаций будет иметь отношение кдругой, а однонаправленный нет.

Это однонаправленная ассоциация

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

Разница в том, содержит ли группа ссылку на пользователя.

Так что мне интересно, единственное ли это отличие?что рекомендуется?

Ответы [ 4 ]

128 голосов
/ 19 марта 2011

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

Обратите внимание, что навигационный доступ не всегда хорош, особенно для отношений "один к очень многим" и "многие к очень многим". Представьте себе Group, который содержит тысячи User с:

  • Как бы вы получили к ним доступ? При таком количестве User s вам обычно нужно применить некоторую фильтрацию и / или нумерацию страниц, чтобы вам все равно нужно было выполнить запрос (если вы не используете фильтрацию коллекции , что для меня выглядит как хак) , Некоторые разработчики могут применять фильтрацию в памяти в таких случаях, что явно не сказывается на производительности. Обратите внимание, что наличие таких отношений может побудить разработчиков такого рода использовать их без учета последствий для производительности.

  • Как бы вы добавили новые User s к Group? К счастью, Hibernate при сохранении смотрит на сторону-владельца отношений, поэтому вы можете установить только User.group. Однако, если вы хотите, чтобы объекты в памяти были единообразными, вам также необходимо добавить User к Group.users. Но это заставит Hibernate извлечь все элементы Group.users из базы данных!

Итак, я не могу согласиться с рекомендацией Best Practices . Вам необходимо тщательно спроектировать двунаправленные отношения, учитывая варианты использования (нужен ли вам навигационный доступ в обоих направлениях?) И возможные последствия для производительности.

Смотри также:

15 голосов
/ 08 февраля 2018

Есть два основных различия.

Доступ к сторонам ассоциации

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

Таким образом, для однонаправленной ассоциации @ManyToOne это означает, что вы можете получить доступ только к той стороне дочернего объекта, где находится внешний ключ.

Если у вас есть однонаправленная ассоциация @OneToMany, это означает, что вы можете получить доступ только к родительской стороне, где находится внешний ключ.

Для двунаправленной ассоциации @OneToMany вы можете перемещаться по ассоциации обоими способами, либо с родительской, либо с дочерней стороны.

Вам также необходимо использовать служебные методы добавления / удаления для двунаправленных ассоциаций, чтобы убедиться, что обе стороны правильно синхронизированы .

Производительность

Второй аспект связан с производительностью.

  1. Для @OneToMany, однонаправленные ассоциации не работают так же хорошо, как двунаправленные .
  2. Для @OneToOne, двунаправленная ассоциация приведет к активному извлечению родителя, если Hibernate не может сказать, должен ли быть назначен прокси или нулевое значение .
  3. Для @ManyToMany, тип сбора имеет большое значение, так как Sets работает лучше, чем Lists.
10 голосов
/ 26 июля 2013

С точки зрения кодирования, двунаправленное отношение является более сложным для реализации, потому что приложение отвечает за синхронизацию обеих сторон согласно спецификации JPA 5 (на странице 42). К сожалению, приведенный в спецификации пример не дает более подробной информации, поэтому он не дает представления об уровне сложности.

Когда не используется кэш второго уровня, обычно нет проблем с неправильной реализацией методов отношений, поскольку экземпляры отбрасываются в конце транзакции.

Если при использовании кэша второго уровня что-либо повреждено из-за неправильно реализованных методов обработки отношений, это означает, что другие транзакции также будут видеть поврежденные элементы (кэш второго уровня является глобальным).

Правильно реализованные двунаправленные отношения могут упростить запросы и код, но их не следует использовать, если они не имеют смысла с точки зрения бизнес-логики.

9 голосов
/ 19 марта 2011

Я не уверен на 100%, что это разница only , но разница main . Также рекомендуется иметь двунаправленные ассоциации в документах Hibernate:

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

В частности:

Предпочитают двунаправленные ассоциации: Однонаправленные ассоциации сложнее запрашивать. В большом приложение, почти все ассоциации должен быть судоходным в обоих направлениях в запросах.

У меня лично есть небольшая проблема с этой общей рекомендацией - мне кажется, есть случаи, когда у ребенка нет практической причины узнать о своем родителе (например, зачем нужен элемент заказа *) 1017 *, чтобы узнать о порядке, с которым он связан?), Но я также вижу ценность в нем разумную часть времени. И поскольку двунаправленность на самом деле ничего не ранит, я не нахожу это слишком нежелательным для соблюдения.

...