如何实现单向一对多的自引用关系?

时间:2015-08-08 00:15:45

标签: java hibernate jpa self-reference

我有一个"问题"我可以坚持的实体"问题"表。一个问题可以有多个翻译。翻译只是使用parent_id字段与其父问题相关联的另一种语言中的另一个问题。因此,Question表包含了question_id(int),parent_id(int),language(varchar),prompt等列。在我的设计中,parent_id与翻译的question_id相同。例如,让我说我的英语(默认)为id 13和17,问题13有中文,日文和韩文三种翻译。然后问题表如下所示:

question_id parent_id language

13 p 13英语; 14 13中国人; 15 13日本人; 16 13韩国人; 17 17英语

在Question对象中,我想要映射问题与其翻译的关系,这是@OneToMany自引用关系。在做了一些研究之后,我已经按照以下方式实现了它:

@Entity
@Table(name = "question")
public class Question {

    @Id
    @GeneratedValue
    @Column(name = "id")
    private Integer id;

    @ManyToOne(cascade=CascadeType.PERSIST)
    @JoinColumn(name="parent_id")
    private Question parent;

    @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
    private Set<Question> translations;

    Other properties...
    Getters and setters....
}

但是,由于它是一种自引用关系,我不理解以下内容:

  • 这是单向还是双向关系?
  • 注释级联= CascadeType.PERSIT对&#34; parent&#34;的影响是什么?字段或在这种情况下它意味着什么?
  • 是否可以替换&#34;父母&#34;整数字段&#34; parent_id&#34;并仍然保持这种关系?换句话说,我可以用Integer&#34; parent_id&#34;跟踪父母。而不是像现在这样拥有整个Question对象:private Question parent

2 个答案:

答案 0 :(得分:1)

  
      
  • 这是单向还是双向关系?
  •   

您拥有的是自我引用的双向关系。这只是标准双向关系的一个特例。

  
      
  • “父”字段上的注释级联= CascadeType.PERSIT会产生什么影响或者它在这意味着什么   情况?
  •   

在这种情况下,按照你的例子,这意味着如果你在问题14中设置parent 13,只是为问题14调用persist,那么Querstion 13也会被保留。

我鼓励看到JPA规范知道会发生什么(这里是JPA 2.1 spect)。

  
      
  • 是否可以用Integer“parent_id”替换“父”字段并仍保持关系?换句话说,我可以   只需使用Integer“parent_id”而不是跟踪父级   拥有像我现在一样的整个Question对象:private Question   父
  •   

是的,您可以进行以下替换,

//@ManyToOne(cascade=CascadeType.PERSIST)
//@JoinColumn(name="parent_id")
//private Question parent;
@Column(name="parent_id", insertable=false, updatable=false)
private Integer parentId;

//@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
@JoinColumn(name="parent_id")
private Set<Question> translations;

关于的一些注释,

  • 不需要translations个集合的级联持久选项。由于这种关系不再是双向的,您可以将问题14,15和16添加到问题13的集合中,并将其与其集合一起保存。
  • 在常见情况下,parentId属性将在添加问题时更新或将其移动到某个集合(这会启动更新语句以设置字段parent_id的值)。没有必要手动修改属性,因此我将insertableupdateble选项添加并设置为 false

答案 1 :(得分:0)

在这里,您需要将问题与翻译分开,创建一个问题实体:

@Entity
public class Question {
  private int id;
  //other independent translation properties
}

@Entity
public class QuestionTranslation{
  private int id;

  @ManyTone
  private Question question;
  private Language language;
  private String translation'
  //more translation based info
}

这样,你就不需要父,子东西之间的复杂化。