【问题标题】:Child's id not present after cascade persisting the parent级联坚持父母后,孩子的身份证不存在
【发布时间】:2015-12-11 15:38:02
【问题描述】:

我有一个 User(父)和一个 Home(子)实体,它们遵循单向的一对多关系。

我的问题是,当向User 添加新的Home 时,新创建和持久化的Home 没有id。这是正常的吗?如果我想要 id,是否需要手动持久化孩子?

这些是我的实体:

@Entity
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @NotNull
    @Column(name = "firstName")
    private String firstName;

    @NotNull
    @Column(name = "lastName")
    private String lastName;

    @NotNull
    @Column(name = "email")
    private String email;

    @OneToMany(targetEntity = Home.class, fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval = true)
    @JoinColumn(name = "userId", referencedColumnName = "id", nullable = false)
    private List<Home> homes;


    public User() {
    }

    public void addHome(Home home) {
        homes.add(home);
    }
}



@Entity
@Table(name = "home")
public class Home implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @NotNull
    @Column(name = "isActive")
    private Boolean isActive;


    public Home() {
    }

}

以及更新父级的代码:

Home home = HomeParser.parse(homeDTO);
User user = userService.findById(userId);
user.addHome(home);
userService.update(user); // delegate call to getEntityManager().merge(user);

在这一点上,我假设我将拥有home 拥有它在持久化到 db 时刚刚给出的 id,但事实并非如此。

我已经尝试将 insertable = false 添加到主页的 id 的 @Column,正如 here 所指出的那样,但它也不起作用。

【问题讨论】:

  • 如果你为你的私有 id 字段添加公共设置器有什么不同吗? (建议为所有字段设置公共 getter 和 setter。)
  • @SteveChambers 我在编辑中删除了这些,但我有 Lombok Getter 和 Setter 注释

标签: java hibernate jpa one-to-many


【解决方案1】:

EntityManager.merge 方法实现委托给 Hibernate Session.merge:

将给定对象的状态复制到持久对象上 相同的标识符。如果当前没有持久化实例 与会话关联,它将被加载。返回持久的 实例。 如果给定实例未保存,请保存 将其作为新的持久实例返回。给定的实例不 与会话相关联。此操作级联到 如果关联被映射,则关联实例 cascade="merge".

注意粗体部分。基本上,merge 操作将级联到您创建的 Home 实例,但 Hibernate 将创建该实例的副本,将您的实例合并到副本中,保存副本并将您的实例替换为 @987654327 中的副本@收藏。

在此之后,User.homes 集合应包含具有正确初始化 id 的 Home 实例的副本。

【讨论】:

  • 谢谢,但这就是问题所在,刚刚添加到User.homeshome 甚至在与副本合并. It doesn't replace the original home 之后也不包含id,因为当我调试时,调试级别 id 不会改变。
  • 能否在userService.update(user)下方添加以下代码:for (Home home : userService.findById(userId).getHomes()) { System.out.println(home.getId()); }?输出是什么?
  • 关于边界,我只有Transactional Dao 级别。你是对的,merge() 返回的user 实例有一个新的home 并具有正确填充的ID。原始实例和mergedUser 实例实际上是两个不同的实例。
  • 没错。然后你必须将merge方法的结果从dao和服务中返回:user = userService.update(user)。然后在其余代码中使用新返回的用户(无论如何,这是使用 merge 方法时的标准方法)。
  • @user3529850 不,如果定义了级联,merge 操作将从根传播到整个对象图。
猜你喜欢
  • 2014-03-16
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
相关资源
最近更新 更多