Как использовать аннотации, связанные с Hibernate @ Any? - PullRequest
29 голосов
/ 20 октября 2008

Может ли кто-нибудь объяснить мне, как аннотации, связанные с Any (@Any, @AnyMetaDef, @AnyMetaDefs и @ManyToAny) работают на практике. Мне трудно найти какую-либо полезную документацию (один JavaDoc не очень полезен) по этому поводу.

До сих пор я понял, что они каким-то образом позволяют ссылаться на абстрактные и расширенные классы. Если это так, то почему нет аннотации @OneToAny? И относится ли это «любое» к единственному «любому» или множеству «любых»?

Был бы очень признателен за короткий, практичный и иллюстрирующий пример (не нужно компилировать).

Редактировать: Столько, сколько я хотел бы принять ответы в качестве ответов и отдать должное в случае необходимости, я нашел ответы Smink и Sakana информативным. Поскольку я не могу принять несколько ответов как ответ , я, к сожалению, не буду отмечать ни один из ответов.

Ответы [ 4 ]

24 голосов
/ 20 октября 2008

Надеюсь, что статья проливает свет на тему:

Иногда нам нужно отобразить ассоциация собственности на разные типы объектов, которые не имеют сущность общего предка - так просто полиморфная ассоциация не делает работа.

Например, давайте предположим три различных приложения, которые управляют библиотекой мультимедиа: первое приложение управляет заимствованием книг, второе DVD-диски и третье VHS. Приложения не имеют ничего общего. Теперь мы хотим разработать новое приложение, которое управляет всеми тремя типами носителей и повторно использует существующие сущности Book, DVD и VHS. Так как классы Book, DVD и VHS были из разных приложений, у них нет предков - общим предком является java.lang.Object. Тем не менее, мы хотели бы иметь один объект Borrow, который может ссылаться на любой из возможных типов медиа.

Чтобы решить этот тип ссылок, мы можем использовать любое отображение. это отображение всегда включает в себя более одного столбца: один столбец содержит тип объекта, к которому относится текущее сопоставленное свойство, а другой - идентификатор объекта, например, если мы ссылаемся на книгу, в первом столбце будет указан маркер тип сущности Book и второй будет содержать идентификатор конкретной книги.

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

}
22 голосов
/ 20 октября 2008

Аннотация @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 представляет тип свойства идентификатора целевых объектов, а мета-тип - тип метаданных (обычно 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() {

Src: Справочное руководство по Hibernate 3.4.0GA

Надеюсь, это поможет!

2 голосов
/ 20 октября 2008

Читали ли вы документацию Hibernate Annotations для @ Any ? Я еще этим не пользовался, но это похоже на расширенный способ определения ссылок. Ссылка включает пример, хотя я не знаю, достаточно ли этого, чтобы полностью понять концепцию ...

1 голос
/ 06 октября 2015

Аннотация @Any определяет полиморфную ассоциацию с классами из нескольких таблиц, но полиморфные ассоциации, подобные этим, являются анти-шаблоном SQL! Основная причина в том, что вы не можете определить ограничение FK, если столбец может ссылаться на несколько таблиц.

Одним из решений, указанных Биллом Карвином в его книге, является создание таблиц пересечений для каждого типа «Любой» вместо использования одного столбца с «типом» и использования уникального модификатора во избежание дублирования. Это решение может быть проблемой при работе с JPA.

Другое решение, также предложенное Карвином, заключается в создании супертипа для связанных элементов. На примере заимствования Book, DVD или VHS вы можете создать супертип Item и сделать наследование Book, DVD и VHS от Item со стратегией объединенной таблицы. Взять потом указывает на пункт. Таким образом, вы полностью избежите проблемы с 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
}
...