В чем разница между однонаправленными и двунаправленными ассоциациями?
Поскольку таблица, сгенерированная в БД, одинакова, единственное различие, которое я обнаружил, состоит в том, что каждая сторона двунаправленных ассоциаций будет иметь ссылку на другую, а однонаправленная - нет.
Это однонаправленная ассоциация
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;
}
Разница в том, содержит ли группа ссылку на пользователя.
Интересно, это единственная разница? что рекомендуется?
Ответы:
Основным отличием является то, что двунаправленные отношения обеспечивают навигационный доступ в обоих направлениях, так что вы можете получить доступ к другой стороне без явных запросов. Также это позволяет применять каскадные параметры в обоих направлениях.
Обратите внимание, что навигационный доступ не всегда хорош, особенно для отношений «один к очень многим» и «многие к очень многим». Представьте себе,
Group
что содержит тысячиUser
с:Как бы вы получили к ним доступ? При таком количестве
User
s обычно вам нужно применить некоторую фильтрацию и / или нумерацию страниц, чтобы вам все равно нужно было выполнить запрос (если только вы не используете фильтрацию коллекции , что для меня выглядит хаком). Некоторые разработчики могут применять фильтрацию в памяти в таких случаях, что явно не сказывается на производительности. Обратите внимание, что наличие таких отношений может побудить разработчиков такого рода использовать их без учета последствий для производительности.Как бы вы добавили новые
User
сGroup
? К счастью, Hibernate при сохранении отношения смотрит на собственную сторону отношений, поэтому вы можете только установитьUser.group
. Однако, если вы хотите, чтобы объекты в памяти были единообразными, вам также необходимо добавитьUser
вGroup.users
. Но это заставит Hibernate извлечь все элементыGroup.users
из базы данных!Так что я не могу согласиться с рекомендацией из Best Practices . Вам необходимо тщательно спроектировать двунаправленные отношения, учитывая варианты использования (нужен ли вам навигационный доступ в обоих направлениях?) И возможные последствия для производительности.
Смотрите также:
источник
setGroup()
отaddUser()
того , чтобы держать обе стороны последовательны.setGroup()
безaddUser()
, но это приведет к несогласованному состоянию объектов в памяти.Есть два основных различия.
Доступ к сторонам ассоциации
Первый связан с тем, как вы получите доступ к отношениям. Для однонаправленной ассоциации вы можете перемещаться по ассоциации только с одного конца.
Таким образом, для однонаправленной
@ManyToOne
ассоциации это означает, что вы можете получить доступ к отношениям только со стороны ребенка, где находится внешний ключ.Если у вас есть однонаправленная
@OneToMany
связь, это означает, что вы можете получить доступ только к той родительской стороне, где находится внешний ключ.Для двунаправленной
@OneToMany
ассоциации вы можете перемещаться по ассоциации обоими способами, либо с родительской, либо с дочерней стороны.Вам также необходимо использовать служебные методы добавления / удаления для двунаправленных ассоциаций, чтобы обеспечить правильную синхронизацию обеих сторон .
Производительность
Второй аспект связан с производительностью.
@OneToMany
, однонаправленные объединения не выполняют, а также двунаправленных из них .@OneToOne
, двунаправленная ассоциация будет вызывать родительскую быть неправдоподобной жадностью , если Hibernate не может сказать , является ли прокси должен быть назначен или нулевое значением .@ManyToMany
, тип коллекции имеет большое значение, так какSets
работают лучше, чемLists
.источник
С точки зрения кодирования, двунаправленное отношение является более сложным для реализации, потому что приложение отвечает за синхронизацию обеих сторон согласно спецификации 5 JPA (на странице 42). К сожалению, приведенный в спецификации пример не дает более подробной информации, поэтому он не дает представления об уровне сложности.
Когда не используется кэш второго уровня, обычно нет проблем с неправильной реализацией методов отношений, поскольку экземпляры отбрасываются в конце транзакции.
При использовании кэша второго уровня, если что-либо повреждено из-за неправильно реализованных методов обработки отношений, это означает, что другие транзакции также будут видеть поврежденные элементы (кэш второго уровня является глобальным).
Правильно реализованные двунаправленные отношения могут упростить запросы и код, но их не следует использовать, если они не имеют смысла с точки зрения бизнес-логики.
источник
Я не уверен на 100%, что это единственная разница, но это главное отличие. Также рекомендуется иметь двунаправленные ассоциации в документах Hibernate:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html
В частности:
У меня лично есть небольшая проблема с этой общей рекомендацией - мне кажется, есть случаи, когда у ребенка нет практической причины знать о своем родителе (например, почему элемент заказа должен знать о заказе, в котором он находится) связано с?), но я вижу ценность в этом разумную часть времени, а также. И поскольку двунаправленность на самом деле ничего не ранит, я не считаю это слишком нежелательным для соблюдения.
источник