如何正确注释处于父子关系中的两个JPA实体?

时间:2013-05-12 16:30:19

标签: jpa eclipselink entity-relationship one-to-many

也许这是一个容易回答的问题......但我没有让它运行。在persist()中,我得到了子表中的引用键为null的异常(数据库当然不允许这样做)。我有一个配方和一些准备步骤。

我正在使用EclipseLink 2.4.1

Recipe.java(rcpid由JPA自动设置)

@Entity
public class Recipe {
    @Id
    long rcpid;

    List<Recipestep> recipesteps = new ArrayList<>();

    @OneToMany(
        cascade=CascadeType.ALL,
        fetch=FetchType.EAGER,
        mappedBy="recipe",
        targetEntity=Recipestep.class )
// This does NOT work. Following line tries to access a join-table !!!
// @JoinColumn(name="rcpid", referencedColumnName="rcpid") 
        public List<Recipestep> getRecipesteps() { return recipesteps; }
    // some more attributes, getters and setters
}

Recipestep.java(rpsid由JPA自动设置)

@Entity
public class Recipestep {
    @Id
    long rpsid;

    Recipe recipe;

    @ManyToOne( targetEntity=Recipe.class )
    @JoinColumn( name="rcpid" )
    public Recipe getRecipe() { return recipe; }

    // some more attributes, getters and setters
}

上面的代码是一种有效的解决方法。但是,为了获得干净(且可支持)的代码,关系应该只与父级中引用其所有子代的集合的单向关系。

2 个答案:

答案 0 :(得分:1)

您已将此映射为单向多对多,但对recipestep rcpid数据库列有两个映射。尝试将long rcpid更改为

@ManyTOne
Recipe rcp;

然后从oneToMany中删除joincolumn定义,并通过将其标记为rcp manyToOne关系映射使其成为双向。这里发布了一个示例http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Relationship_Mappings/Collection_Mappings/OneToMany

首次插入目标实体时,Eclipselink将始终使用joincolumn在单向oneToMany关系上插入空值,然后在处理Recipe实体时更新它。 Recipestep中的rcpid映射也可能为null,这意味着您对同一个字段有两个可写映射,特别是当它们发生冲突时会出现问题。

答案 1 :(得分:0)

您遇到了默认的JPA行为。将实体添加到recipesteps列表不足以创建双向关系。

要解决此问题,您需要在列表中的每个元素上明确设置rcpid

编辑:我认为问题是JPA不知道在Recipestep表中存储Recipe的id的位置。它假设一个名称(“recipebo_rcpid”),但你的表似乎缺少它。

尝试将“recipe_id”列添加到Recipestep表,并将mappedBy属性添加到@OneToMany注释:

@OneToMany(
  cascade=CascadeType.ALL,
  fetch = FetchType.EAGER,
  mappedBy = "recipe" )

您可能不需要注释中的targetEntity属性 - List已经输入。