33

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

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

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

编辑:尽管我想接受答复作为答案并在适当的时候给予信用,但我发现 Smink 和 Sakana 的答案都提供了丰富的信息。因为我不能接受多个回复作为答案,所以很遗憾我将两者都标记为答案。

4

4 回答 4

29

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

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

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

为了解决这种类型的引用,我们可以使用 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;
    }

}
于 2008-10-20T09:15:14.690 回答
24

@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() {

Src:Hibernate Annotations 参考指南 3.4.0GA

希望能帮助到你!

于 2008-10-20T09:26:34.153 回答
4

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

Bill Karwin 在他的书中指出的解决方案之一是为每种类型的“Any”创建交集表,而不是使用带有“type”的列,并使用 unique 修饰符来避免重复。使用 JPA 时,此解决方案可能会很痛苦。

另一个解决方案,也是由 Karwin 提出的,是为连接的元素创建一个超类型。以借用 Book、DVD 或 VHS 为例,可以创建一个超类型 Item,并使 Book、DVD 和 VHS 继承于 Item,采用 Joined table 的策略。借用然后指向项目。这样您就完全避免了 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
}
于 2015-10-06T14:45:35.420 回答
2

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

于 2008-10-20T09:15:09.573 回答