2012-02-28 165 views
12

我使用JPA2与EclipseLink的实施@ManyToOne映射无法保存父ID

![简单的表结构] [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(); 

我没有错误,所有的实体在数据库中坚持着。问题是在小费表story_id字段总是NULL。我可以想象,JPA无法从故事表中获得新的id。这里的正确方法是什么?

LE

在代码的当前状态,该Tip实体仍然存在,但该国ID仍无效。

回答

6

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

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

因此,设定/不设定

story.setTipList(tips) 

是你。但是如果你想改变正常的DB反映,然后你们必须调用

tip.setStory(story) 

Tip是拥有方在这里,按你的代码。 此外你的代码看起来不完整。原因是,

  • storyService.create(newStory)返回的实体被管理,但不是newStory。所以只是设置newStory.setTipList(tips)将不会更新分区
5

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

它的做法是在Story类中创建一个addTip(提示提示)方法。

这种方法做:

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

如果您不需要bedirectional的方法,你可以删除这个故事领域的提示,这将解决您的问题

+1

我想知道是否没有更自动的方式来做到这一点。更重要的是,我真的不认为删除提示中的故事字段是一个聪明的想法,因为这样,他将需要摆脱'@PrimaryKeyJoinColumn(name =“STORY_ID”,referencedColumnName =“ID” )',让JPA不知道应该如何进行加入。这正是我通过阅读这个主题所了解的。如果我错了,请让我知道。 – Dragos 2012-02-28 11:50:26

+0

Ebean有自动解决方案,但JPA实现不提供自动解决方案。 – Palesz 2012-03-08 15:10:14

0

你不应该使用PrimaryKeyJoinColumn,只是JoinColumn,但拥有完整的课程有助于给出特定的答案。

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

+0

嗨!感谢您的答复!我更新了我的问题。我添加了所有实体属性以及在更改'@ PrimaryKeyJoinColumn'注释后发生的更改。我希望现在更清楚。 – Ionut 2012-02-28 14:38:10

1

卸下

@Column(名称= “STORY_ID”) 私人整数storyId;

您已经声明它@JoinColumn(name =“STORY_ID”,referencedColumnName =“ID”)

那就是为什么你所得到的错误多可写的映射存在的领域tip.STORY_ID]

+0

谢谢!事实上,没有其他错误,但'提示'实体不再被持久 – Ionut 2012-02-28 17:35:47

+0

根据实现,在双向关系中,你必须设置关系的两种方式(我不确定是否在eclipselink中是这样的,但它可以值得一试)。因此,尝试将newStory设置为列表提示的每个提示。另外,行“boolean completed = storyService.create(newStory);”在transaction.commit之前放置它会是更多的逻辑; – Pau 2012-02-29 10:16:31