Hibernate多态性

ae6*_*6rt 12 java polymorphism hibernate

这是Hibnerate多态性问题和数据模型设计问题; 他们正在交织.我过去曾经使用过Hibernate,并且很享受它,但有时我发现很难想到除了琐碎的设计之外的任何东西.不是对Hibernate的敲门声; 只是观察到ORM通常具有挑战性.

我认为这是一个Hibernate 101问题,但我不确定.我想要实现的目标甚至可能无法实现.

我有一个抽象类Fruit,它将被子类化为Apple和Orange.我有一个Note类,代表关于苹果和橘子的注释或评论.Apple或Orange可以有许多与之关联的Notes,但只有一个Apple或Orange将与给定的Note相关联.

这是类的草图,我现在在这里省略对象id的去向,以及将它们与Orange区分开的Apples的属性.目前,我对使用哪种Hibernate继承策略并不感到强烈.

abstract public class Fruit {
}

// Apples have notes written about them:
public class Apple extends Fruit {
   private Set<Note> note;
   ...

   @OneToMany(cascade = CascadeType.ALL)
   public Set<Note> getNote() {
       return note;
   }
}


// Oranges have notes written about them:
public class Orange extends Fruit {
   private Set<Note> note;
   ...

   @OneToMany(cascade = CascadeType.ALL)
   public Set<Note> getNote() {
       return note;
   }
}
Run Code Online (Sandbox Code Playgroud)

这是当前实现的Note类,其中我们看到它包含Apple和Orange的字段.这种设计的缺陷或不足之处在于,单个音符实例仅指向Apple或Orange之一,而不是两者.因此,如果一个Note被绑定到Apple,那么Orange字段是多余的并且不雅观,反之亦然.

// A note about an Apple or Orange
public class Note {
   private String theNote;
   private Apple apple; 
   private Orange orange;
   ...

   // with the usual many to one mapping
   @ManyToOne
   @JoinColumn(name = "apple_id")
   public Apple getApple() { 
       return apple;
   }

   // with the usual many to one mapping
   @ManyToOne
   @JoinColumn(name = "orange_id")
   public Orange getOrange() {
       return orange;
   }

   ...
}
Run Code Online (Sandbox Code Playgroud)

但是,这是Note类,我认为我想基于我的设计,但我不确定如何考虑Hibernate注释和表映射:

// A note about a fruit:
public class Note {
   private String theNote;
   private Fruit fruit;
   ...
}
Run Code Online (Sandbox Code Playgroud)

因此水果将是Apple或Orange实例.

可以使用后面的Note类,它实际上持有Apple或Orange的Fruit,甚至可以与Hibernate ORM映射协调一致吗?如果是,有人可以谈谈如何.

Hen*_*ing 15

这绝对是可能的.您可以将注释与抽象Fruit类相关联,而不是在每个实现中重复它们:

@Entity
@Inheritance
public abstract class Fruit {
   private Set<Note> notes;
   ...

   @OneToMany(cascade = CascadeType.ALL, mappedBy = "fruit")
   public Set<Note> getNotes() {
       return notes;
   }
}

@Entity
public class Apple extends Fruit {
   ...
}


@Entity
public class Orange extends Fruit {
   ...
}

@Entity
public class Note {
   private String theNote;

   @ManyToOne
   private Fruit fruit;
   ...
}
Run Code Online (Sandbox Code Playgroud)

Étvoilà!

- 基于注释的添加: JPA提供了多种处理继承的策略.Java EE教程中相关部分应该可以帮助您入门.

基本上,您的选择是:

  • 将所有内容存储在一个表中并使用鉴别器列来了解哪一行是哪种类型
  • 将每个具体类(Apple和Orange)存储在单独的表中
  • 有一个带有鉴别器列的公共Fruit表,以及带有Fruit表外键的Apple和Orange表

另一个编辑: 注意这是一个Hibernate,而不是一个JPA问题.但是,不会产生太大的差别,因为选项是相同的.这是Hibernate文档中相关部分.


Il-*_*ima 5

这种模式在基于Hibernate的数据层中非常常见。它在内部的工作方式很大程度上取决于使用哪种继承策略。

当使用每个类的表或每个子类的继承表时,将为每个子类/类创建一个表。例如,在您的情况下,您将有一个表Fruit和两个表AppleOrange,并且在Fruit和Apple / Orange之间具有外键引用。当通过ID请求单个水果(苹果或橙子)时,Hibernate会将Fruit表与Apple和Orange表外部连接。每行将转换为Apple或Orange,具体取决于从中检索字段的表。

另一种可能性是使用鉴别符。Fruit将使用单个表,该表将包含一个鉴别符字段(例如fruit_type,取值appleorange)。根据该字段的值,Hibernate将确定相应的对象是Apple还是Orange。

在您的情况下,在急于加载的情况下,当Hibernate加载Note对象时,它将急切地获取相应的Fruit并相应地用Apple或Orange实例填充Fruit字段。

在延迟获取的情况下,fruit字段将是实现Fruit接口的代理。在实际的水果田被装载之前,其类型尚未确定。

希望这能回答您的一些疑问。