【问题标题】:@ManyToOne mapping fails to save parent ID@ManyToOne 映射无法保存父 ID
【发布时间】:2012-03-17 20:10:55
【问题描述】:

我正在使用 JPA2 和 EclipseLink 实现

![简单表结构][1]

这是我尝试映射的两个表和 JPA 注释。

public class Story implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    Integer id;
    @Temporal(TemporalType.TIMESTAMP)
    @Column (name="DATE_CREATED")
    Date dateCreated;
    String title;
    String description;
    @Column(name="AUTHOR_ID")
    Integer authorId;
    @Column(name="COUNTRY_ID")
    Integer countryId;
    private String reviews;

    @OneToMany(mappedBy = "story", cascade=CascadeType.ALL)
    private List<Tip> tipList;
}

public class Tip implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer id;
    private String description;
    private Integer vote;

    @ManyToOne (cascade=CascadeType.ALL)
    @JoinColumn(name="STORY_ID", referencedColumnName="ID")
    private Story story;
}

作为一个简单的例子,我想在同一个事务中保留一个故事和一些与故事相关的提示。 这是执行此操作的代码部分:

Story newStory = new Story(title, body, ...);

EntityTransaction transaction = em.getTransaction().begin();
    boolean completed = storyService.create(newStory);
    //The tips are saved as a List<String>. This methods creates the needed List<Tip> from the Strings
    List<Tip> tips = TipUtil.getTipList(tipList);
    newStory.setTipList(tips)
transaction.commit();

我没有错误,所有实体都保存在数据库中。问题在于,在 tip 表 中,story_id 字段始终为 NULL。我可以想象 JPA 无法从故事表中获取新的id。这里的正确方法是什么?

LE

在代码的当前状态下,Tip 实体保持不变,但国家/地区 ID 保持为空。

【问题讨论】:

    标签: java jpa entity-relationship


    【解决方案1】:

    因为您需要更新每个孩子的父链接故事。

    它的完成方式是在你的 Story 类中创建一个 addTip(Tip tip) 方法。

    这个方法可以:

    tip.setStory(this);
    tipList.add(tip);
    

    如果您不需要定向方法,您可以删除提示中的故事字段,它将解决您的问题

    【讨论】:

    • 我想知道是否没有更自动的方法来做到这一点。更重要的是,我真的不认为删除 Tip 中的故事字段会是一个聪明的主意,因为这样,他需要摆脱`@PrimaryKeyJoinColumn(name="STORY_ID", referencedColumnName="ID" )`,让 JPA 不知道它应该如何进行连接。这正是我通过阅读有关该主题的一些内容所理解的。如果我错了,请告诉我。
    • Ebean 对此有自动解决方案,但 JPA 实现不提供自动解决方案。
    【解决方案2】:

    您不应该使用 PrimaryKeyJoinColumn,而应该使用 JoinColumn,但是拥有完整的课程将有助于给出一定的答案。

    PrimaryKeyJoinColumn 仅在 story_id 也是 Tip 的 id(Tip 中没有 id)并且存在重复的基本映射时才使用。它应该很少使用,并且在 JPA 2.0 中不再需要,因为不再需要重复的 id 映射。

    【讨论】:

    • 嗨!谢谢您的答复!我更新了我的问题。我添加了所有实体属性以及更改@PrimaryKeyJoinColumn 注释后发生的更改。我希望现在更清楚了。
    【解决方案3】:

    删除

    @Column(name = "STORY_ID") 私有整数故事 ID;

    您已经在 @JoinColumn(name="STORY_ID", referencedColumnName="ID") 中声明它

    这就是为什么您收到错误 Multiple writable mappings exists for the field [tip.STORY_ID]

    【讨论】:

    • 谢谢!确实没有其他错误,但 Tip 实体不再保留
    • 根据实现的不同,在双向关系中,您必须设置关系的两种方式(我不确定在 eclipselink 中是否是这样,但值得一试)。因此,尝试将 newStory 设置为列表提示的每个提示。此外,“boolean completed = storyService.create(newStory);”行将它放在 transaction.commit 之前会更符合逻辑;
    【解决方案4】:

    使用 JPA,始终建议以双向关系更新双方的关系。这是为了确保数据在你的应用层是一致的,与数据库无关。

    但是,您必须在双向关系中更新关系的拥有方。

    所以,设置/不设置

    story.setTipList(tips)
    

    由你决定。但是,如果您希望更改在 DB 中正确反映,那么您必须调用

    tip.setStory(story)
    

    根据您的代码,Tip 是这里的所有者。 你的代码对我来说也不完整。原因是,

    • storyService.create(newStory) 返回的实体是托管的,但不是newStory。所以只设置newStory.setTipList(tips) 不会更新数据库

    【讨论】:

      猜你喜欢
      • 2017-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-02
      • 2013-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多