JPA多态oneToMany

时间:2010-05-26 16:38:07

标签: java jpa polymorphism

我无法弄清楚如何使用JPA干净地执行标记云,其中每个数据库实体可以包含许多标记。

E.g

帖子可以有0个或更多标签 用户可以拥有0个或更多标签

在JPA中是否有一种更好的方法,而不是让所有实体都像Taggable抽象类那样进行子类化? Tag实体将引用许多Taggables。

编辑:标签云只是简化我遇到的问题的一个示例。在我的场景中,关系应该是OneToMany,其中Tag不能被重用。

谢谢

4 个答案:

答案 0 :(得分:1)

这看起来像ManyToMany,而不是一对多。用户可以拥有多个标签,标签可以与多个用户相关联吗?

如果您希望能够将标记与包含标记有该标记的每个对象的单个集合建立关系,则只需要这样的超类。您是否需要tag.getOneGiantCollectionOfEveryTaggedEntity()方法?

由于标记的对象似乎没有任何共同点,这样的集合在您的应用程序域中是否真的具有任何价值?它表面上也可能非常大,而且无论如何你都不想通过对象关系来处理它。从实际的角度来看,在不了解您的用例的情况下,似乎tag.getTaggedUsers()tag.getTaggedPosts()等更有用。

对不起,我猜我要问的问题多于给出答案,但目前还不清楚你希望你的完成对象域看起来像什么:)

编辑:

也许问题的实际答案只是“不,Hibernate不会为你绘制一个没有共同祖先的原始类型的原始集合,只会碰到所有人都有你的实体的外键。”你不必在你的实体上强加一个'假的'超类,但如果你不这样做,你就必须建立一个连接表。

答案 1 :(得分:1)

  

JPA中有没有比让所有实体都像Taggable抽象类子类更好的方法?

让我们忘记这个例子:) JPA确实支持多态关联,但目标类必须是继承层次结构的一部分。以下是关于继承策略的更多经验法则:

  
      
  • SINGLE_TABLE:      
        
    • 层次结构中的所有类都映射到单个表
    •   
    • 这种策略提供了良好的支持多态关系   覆盖的实体和查询   整个类层次结构。
    •   
    • 可能包含某些子类数据的空字段
    •   
  •   
  • TABLE_PER_CLASS:      
        
    • 层次结构中的每个类都映射到一个单独的表,因此提供   对多态性的支持不足   关系
    •   
    • 需要SQL联合或每个子类的单独SQL查询
    •   
  •   
  • JOINED      
        
    • no null fields =>紧凑数据
    •   
    • 这为多态关系提供了很好的支持,但是   需要一个或多个连接操作 -   可能会导致表现不佳
    •   
  •   

简而言之,如果您的子类声明的属性相对较少,则更喜欢SINGLE_TABLE策略。如果没有,请使用JOINED策略,除非您拥有深层次结构(在这种情况下,联接的成本可能会比联盟更昂贵,然后TABLE_PER_CLASS会“更差”)。

参考

  • JPA 1.0规范
    • 第2.1.9节“继承”
    • 第2.1.10节“2.1.10继承映射策略”

答案 2 :(得分:0)

为什么你不只是映射一个标签集合甚至是字符串?

sudocode:

@Entity
@Table(name="entities")
class MyEntity{
    long id;
    String someField;
    @ManyToMany(targetEntity=Tag.class)
    @JoinTable(name="entities_to_tags",
         joinColumns={
             @JoinColumn(name="id",  
             referencedColumnName="entity_id",
             inverseJoinColumns={
                 @JoinColumn(name="id", referencedColumnName="tag_id")})
    List<Tag> tags;
    [...getter&setter...]
}

@Entity
@Table(name="tags")
class Tag{
    @Id
    @GeneratedValue
    long id;
    String title;
    [....getter & setter...]
}

答案 3 :(得分:0)

如果您不需要多态性查询,例如“get everything tagged tagged Foo”,那么您还可以引入一个新实体(比如TaggingTarget),并从{创建单向一对一关系{1}} {({1}}等)到User以及PostTaggingTarget之间的多对多关系:

TaggingTarget

与Affe的解决方案的不同之处在于,您不需要Tag@Entity public class User { @OneToOne private TaggingTarget target; ... } @Entity public class TaggingTarget { @ManyToMany(...) private Set<Tag> tags; ... } @Entity public class Tag { @ManyToMany(...) private Set<TagTarget> targets; ... } 等,并且可以在不更改tag.getTaggedUsers()的情况下添加新标记的实体。可以使用JPQL查询标记的实体:

tag.getTaggedPosts()

Tag