Может ли кто-нибудь объяснить мне, как аннотации Any-related (@Any, @AnyMetaDef, @AnyMetaDefs и @ManyToAny) работают на практике. Мне сложно найти какую-либо полезную документацию (сам по себе JavaDoc не очень полезен) по этим вопросам.
До сих пор я понял, что они каким-то образом позволяют ссылаться на абстрактные и расширенные классы. Если это так, то почему нет аннотации @OneToAny? И относится ли это «любое» к одному «любому» или нескольким «любым»?
Очень хотелось бы получить краткий, практичный и иллюстративный пример (не обязательно компилировать).
Редактировать: насколько бы я ни хотел принимать ответы в качестве ответов и отдавать должное, когда это необходимо, я нашел ответы как Smink, так и Sakana информативными. Поскольку я не могу принять несколько ответов как ответ, я, к сожалению, не помечу ни один из них как ответ.




Вы читали документация Hibernate Annotations для @Any? Сам еще не использовал его, но похоже, что это какой-то расширенный способ определения ссылок. Ссылка включает пример, хотя я не знаю, достаточно ли этого, чтобы полностью понять концепцию ...
Надеюсь, этот статья проливает свет на эту тему:
Sometimes we need to map an association property to different types of entities that don't have a common ancestor entity - so a plain polymorphic association doesn't do the work.
Например, предположим, что три разных приложения управляют медиа-библиотекой - первое приложение управляет заимствованием книг, второе - DVD, а третье - VHS. Между приложениями нет ничего общего. Теперь мы хотим разработать новое приложение, которое управляет всеми тремя типами носителей и повторно использует существующие объекты Book, DVD и VHS. Поскольку классы Book, DVD и VHS были получены из разных приложений, у них нет никакого предка - общим предком является java.lang.Object. Тем не менее, мы хотели бы иметь одну сущность «Заимствование», которая может относиться к любому из возможных типов мультимедиа.
Чтобы решить этот тип ссылок, мы можем использовать отображение any. это сопоставление всегда включает более одного столбца: один столбец включает тип объекта, к которому относится текущее сопоставленное свойство, а другой включает идентификатор объекта, например, если мы ссылаемся на книгу, первый столбец будет включать маркер для тип сущности "Книга", а второй будет включать идентификатор конкретной книги.
@Entity
@Table(name = "BORROW")
public class Borrow{
@Id
@GeneratedValue
private Long id;
@Any(metaColumn = @Column(name = "ITEM_TYPE"))
@AnyMetaDef(idType = "long", metaType = "string",
metaValues = {
@MetaValue(targetEntity = Book.class, value = "B"),
@MetaValue(targetEntity = VHS.class, value = "V"),
@MetaValue(targetEntity = DVD.class, value = "D")
})
@JoinColumn(name = "ITEM_ID")
private Object item;
.......
public Object getItem() {
return item;
}
public void setItem(Object item) {
this.item = item;
}
}
Аннотация @ Any определяет полиморфную ассоциацию с классами из нескольких таблиц. Этот тип отображения всегда требует более одного столбца. Первый столбец содержит тип связанной сущности. Остальные столбцы содержат идентификатор. Невозможно указать ограничение внешнего ключа для такого рода ассоциации, поэтому это определенно не подразумевается как обычный способ отображения (полиморфных) ассоциаций. Вы должны использовать это только в очень особых случаях (например, журналы аудита, данные сеанса пользователя и т. д.). Аннотация @Any описывает столбец, содержащий информацию о метаданных. Чтобы связать значение метаданные и фактический тип объекта, используются аннотации @AnyDef и @AnyDefs.
@Any( metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
@AnyMetaDef(
idType = "integer",
metaType = "string",
metaValues = {
@MetaValue( value = "S", targetEntity = StringProperty.class ),
@MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
@JoinColumn( name = "property_id" )
public Property getMainProperty() {
return mainProperty;
}
idType представляет тип свойства идентификатора целевых сущностей, а metaType - тип метаданных (обычно String). Обратите внимание, что @AnyDef можно объединять и использовать повторно. Рекомендуется разместить его как метаданные пакета в этом кейс.
//on a package
@AnyMetaDef( name = "property"
idType = "integer",
metaType = "string",
metaValues = {
@MetaValue( value = "S", targetEntity = StringProperty.class ),
@MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
package org.hibernate.test.annotations.any;
//in a class
@Any( metaDef = "property", metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
@JoinColumn( name = "property_id" )
public Property getMainProperty() {
return mainProperty;
}
@ManyToAny допускает полиморфные ассоциации с классами из нескольких таблиц. Этот тип сопоставления всегда требует более одного столбца. Первый столбец содержит тип связанной сущности. Остальные столбцы удерживайте идентификатор. Невозможно указать ограничение внешнего ключа для такого рода ассоциации, поэтому это наиболее конечно не подразумевается как обычный способ отображения (полиморфных) ассоциаций. Вы должны использовать это только в очень особые случаи (например, журналы аудита, данные сеанса пользователя и т. д.).
@ManyToAny(
metaColumn = @Column( name = "property_type" ) )
@AnyMetaDef(
idType = "integer",
metaType = "string",
metaValues = {
@MetaValue( value = "S", targetEntity = StringProperty.class ),
@MetaValue( value = "I", targetEntity = IntegerProperty.class ) } )
@Cascade( { org.hibernate.annotations.CascadeType.ALL } )
@JoinTable( name = "obj_properties", joinColumns = @JoinColumn( name = "obj_id" ),
inverseJoinColumns = @JoinColumn( name = "property_id" ) )
public List<Property> getGeneralProperties() {
Источник: Справочное руководство по аннотациям Hibernate 3.4.0GA
Надеюсь, это поможет!
Я знаю, что это примерно на 6 лет позже, но этот последний бит @ManyToAny спас мою задницу. Я нигде не видел, чтобы это упоминалось, и это почти единственный способ сопоставить список объектов, унаследованных от одного объекта.
Хотел бы я больше одного раза
Аннотация @Any определяет полиморфную ассоциацию с классами из нескольких таблиц, верно, но полиморфные ассоциации, подобные этим, являются анти-шаблоном SQL! Основная причина в том, что вы не можете определить ограничение FK, если столбец может ссылаться на более чем одну таблицу.
Одно из решений, указанное Биллом Карвином в своей книге, состоит в создании таблиц пересечений для каждого типа «Любой» вместо использования одного столбца с «типом» и использования модификатора unique, чтобы избежать дублирования. Это решение может быть проблемой при работе с JPA.
Другое решение, также предложенное Карвином, - создать супертип для связанных элементов. Взяв пример заимствования книги, DVD или VHS, вы можете создать элемент супертипа и сделать так, чтобы книги, DVD и VHS унаследовали от элемента со стратегией объединенной таблицы. Затем заимствовать указывает на Предмет. Таким образом вы полностью избежите проблемы FK. Я перевел пример книги на JPA ниже:
@Entity
@Table(name = "BORROW")
public class Borrow{
//... id, ...
@ManyToOne Item item;
//...
}
@Entity
@Table(name = "ITEMS")
@Inheritance(strategy=JOINED)
public class Item{
// id, ....
// you can add a reverse OneToMany here to borrow.
}
@Entity
@Table(name = "BOOKS")
public class Book extends Item {
// book attributes
}
@Entity
@Table(name = "VHS")
public class VHS extends Item {
// VHSattributes
}
@Entity
@Table(name = "DVD")
public class DVD extends Item {
// DVD attributes
}
Я хотел бы отметить, что, согласно книге Билла Карвина, такая практика считается антипаттерном SQL.