2008-10-20 66 views
26

有人可以向我解释任何相关注释(@Any@AnyMetaDef,@AnyMetaDefs@ManyToAny)是如何在实践中工作的。我很难找到任何有用的文档(JavaDoc本身并不是很有用)。如何使用Hibernate @与任何相关的注释?

我迄今为止收集到他们以某种方式启用引用到抽象类和扩展类。如果是这种情况,为什么没有@OneToAny注释?而这个“任何”是指单个“任何”还是多个“任何”?

一个简短,实用和说明的例子将非常赞赏(不必编译)。

编辑:尽可能多的我想接受答复作为答案,并给予信用到期,我发现Smink的和Sakana的答案信息。因为我不能接受几个答复答案,所以不幸的是我不会将其标记为答案。

+1

根据Bill Karwin的书,我想指出这种做法被认为是SQL反模式。 – atorres 2015-10-06 14:26:18

回答

22

希望这article带来一些光的主题:

有时我们需要映射的 关联属性不同 类型的实体没有 共同的祖先实体 - 所以一个普通的 多态关联不会做 的工作。

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

要解决这种类型的引用,我们可以使用任何映射。此映射始终包含多个列:一列包括当前映射属性引用的实体类型,另一列包含实体的标识,例如,如果我们引用书籍,则第一列将包含标记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; 
    } 

} 
19

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

希望它能帮助!

+1

我知道这很晚了6年,但是这最后@ManyToAny位救了我的屁股。在任何地方都没有看到它,它只是映射从单个实体继承的对象列表的唯一方法。 – 2016-12-23 10:52:22

1

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

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

Karwin也提出了另一种解决方案,即为连接元素创建超类型。以借书,DVD或VHS为例,您可以创建一个超级类型的Item,并使得Book,DVD和VHS从Item继承,并带有Join表的策略。借用然后指向项目。这样你完全避免了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 
}