Java 如何使用 Hibernate @Any 相关注解?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/217831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:33:13  来源:igfitidea点击:

How to use Hibernate @Any-related annotations?

javahibernateormannotations

提问by Henrik Paul

Could someone explain to me how Any-related annotations (@Any, @AnyMetaDef, @AnyMetaDefsand @ManyToAny) work in practice. I have a hard time finding any useful documentation (JavaDoc alone isn't very helpful) about these.

有人可以向我解释 Any-related annotations ( @Any, @AnyMetaDef, @AnyMetaDefsand @ManyToAny) 在实践中是如何工作的。我很难找到有关这些的任何有用文档(仅 JavaDoc 不是很有帮助)。

I have thus far gathered that they somehow enable referencing to abstract and extended classes. If this is the case, why is there not an @OneToAnyannotation? And is this 'any' referring to a single 'any', or multiple 'any'?

到目前为止,我已经收集到它们以某种方式能够引用抽象类和扩展类。如果是这种情况,为什么没有@OneToAny注释?这个“任何”是指单个“任何”还是多个“任何”?

A short, practical and illustrating example would be very much appreciated (doesn't have to compile).

一个简短、实用和说明性的例子将非常受欢迎(不必编译)。

Edit:as much as I would like to accept replies as answers and give credit where due, I found both Smink's and Sakana's answers informative. Because I can't accept several replies as the answer, I will unfortunately mark neither as the answer.

编辑:尽管我愿意接受回复作为答案并在适当的时候给予信用,但我发现 Smink 和 Sakana 的回答都提供了信息。因为我不能接受几个回复作为答案,很遗憾我将它们都标记为答案。

回答by Martin Klinke

Have you read the Hibernate Annotations documentation for @Any? Haven't used that one myself yet, but it looks like some extended way of defining references. The link includes an example, though I don't know if it's enough to fully understand the concept...

您是否阅读过 @Any 的 Hibernate Annotations 文档?我自己还没有使用过那个,但它看起来像是一种定义引用的扩展方法。该链接包含一个示例,但我不知道是否足以完全理解该概念...

回答by Jorge Ferreira

Hope this articlebrings some light to the subject:

希望这篇文章能给这个主题带来一些启发:

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.

有时我们需要将关联属性映射到没有共同祖先实体的不同类型的实体——因此普通的多态关联无法完成这项工作。

For example let's assume three different applications which manage a media library - the first application manages books borrowing, the second one DVDs, and the third VHSs. The applications have nothing in common. Now we want to develop a new application that manages all three media types and reuses the exiting Book, DVD, and VHS entities. Since Book, DVD, and VHS classes came from different applications they don't have any ancestor entity - the common ancestor is java.lang.Object. Still we would like to have one Borrow entity which can refer to any of the possible media type.

例如,让我们假设管理媒体库的三个不同应用程序——第一个应用程序管理图书借阅,第二个应用程序管理 DVD,第三个应用程序管理 VHS。这些应用程序没有任何共同之处。现在我们要开发一个新的应用程序来管理所有三种媒体类型并重用现有的 Book、DVD 和 VHS 实体。由于 Book、DVD 和 VHS 类来自不同的应用程序,因此它们没有任何祖先实体——共同的祖先是 java.lang.Object。我们仍然希望有一个可以引用任何可能的媒体类型的 Borrow 实体。

To solve this type of references we can use the any mapping. this mapping always includes more than one column: one column includes the type of the entity the current mapped property refers to and the other includes the identity of the entity, for example if we refer to a book it the first column will include a marker for the Book entity type and the second one will include the id of the specific book.

为了解决这种类型的引用,我们可以使用 any 映射。此映射始终包含多个列:一列包含当前映射属性所指的实体类型,另一列包含实体的标识,例如,如果我们引用一本书,第一列将包含一个标记Book 实体类型,第二个实体类型将包含特定书籍的 id。

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

}

回答by sakana

The @Any annotation defines a polymorphic association to classes from multiple tables. This type of mapping always requires more than one column. The first column holds the type of the associated entity. The remaining columns hold the identifier. It is impossible to specify a foreign key constraint for this kind of association, so this is most certainly not meant as the usual way of mapping (polymorphic) associations. You should use this only in very special cases (eg. audit logs, user session data, etc). The @Any annotation describes the column holding the metadata information. To link the value of the metadata information and an actual entity type, The @AnyDef and @AnyDefs annotations are used.

@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 represents the target entities identifier property type and metaType the metadata type (usually String). Note that @AnyDef can be mutualized and reused. It is recommended to place it as a package metadata in this case.

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 allows polymorphic associations to classes from multiple tables. This type of mapping always requires more than one column. The first column holds the type of the associated entity. The remaining columns hold the identifier. It is impossible to specify a foreign key constraint for this kind of association, so this is most certainly not meant as the usual way of mapping (polymorphic) associations. You should use this only in very special cases (eg. audit logs, user session data, etc).

@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 Annotations Reference Guide 3.4.0GA

源代码:Hibernate Annotations 参考指南 3.4.0GA

Hope it Helps!

希望能帮助到你!

回答by atorres

The @Any annotation defines a polymorphic association to classes from multiple tables, right, but polymorphic associations such as these are an SQL anti-pattern! The main reason is that you can′t define a FK constraint if a column can refer to more than one table.

@Any 注释定义了到来自多个表的类的多态关联,对,但是像这样的多态关联是 SQL 反模式!主要原因是如果一列可以引用多个表,则不能定义 FK 约束。

One of the solutions, pointed out by Bill Karwin in his book, is to create intersection tables to each type of "Any", instead of using one column with "type", and using the unique modifier to avoid duplicates. This solution may be a pain to work with JPA.

Bill Karwin 在他的书中指出的一种解决方案是为每种类型的“Any”创建交集表,而不是使用带有“type”的一列,并使用唯一的修饰符来避免重复。这个解决方案可能很难与 JPA 一起工作。

Another solution, also proposed by Karwin, is to create a super-type for the connected elements. Taking the example of borrowing Book, DVD or VHS, you could create a super type Item, and make Book, DVD and VHS inherit from Item, with strategy of Joined table. Borrow then points to Item. This way you completely avoid the FK problem. I translated the book example to JPA bellow:

Karwin 提出的另一个解决方案是为连接元素创建一个超类型。以借用Book、DVD或VHS为例,您可以创建一个超类型Item,使Book、DVD和VHS继承自Item,采用Joined table的策略。Borrow 然后指向 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
}