Spring 数据 Jpa:来自 parent 个实体的 child 个实体不会更新 child 个身份

Spring Data Jpa: persisting child entities from parent entity does not update child identity

环境:

Spring Data Jpa(或一般的 Jpa)NOT 更新 child 身份属性是否正常 child通过 parent 实体存储库保留(保存)?

考虑一下:

@Entity( name = "Company" )
@Table( name = "COMPANY" )
final public class Company
{
  @Id
  @GeneratedValue( strategy = GenerationType.IDENTITY )
  @Column( name = "ID", updatable = false, nullable = false )
  private Long id = null;

  @OneToMany(
    mappedBy = "company",
    cascade = CascadeType.ALL,
    orphanRemoval = true
  )
  private Set< Phone > phoneSet = new LinkedHashSet<>();

  ...getters/setters...
}

@Entity( name = "Phone" )
@Table( name = "PHONE" )
final public class Phone
{
  @Id
  @GeneratedValue( strategy = GenerationType.IDENTITY )
  @Column( name = "ID", updatable = false, nullable = false )
  private Long id = null;

  @ManyToOne
  @JoinColumn( name = "COMPANY_ID" )
  private Company company = null;

  @Column( name = "number" )
  String number = null;

  ...getters/setters...
}


private void someClassFunction()
{
  .....
  Phone phone = new Phone( company, "1115551234" );
  company.getPhoneSet().add( phone );
  this.companyRespository.save( company );  // <<<< NOTE THIS LINE
  System.out.println( "phone.id: " + phone.getId() );
}

当我调用 someClassFunction() 时,我得到:

phone.id: null

我无法立即使用分配给 id 的数据库。我确实检查了数据库并插入了记录 (persisted/saved),并且 MySQL 确实分配了一个 ID。如果我在另一个函数中重新加载 parent class(公司),child 会重新加载并具有正确的 ID。

但是,如果我将 someClassFunction() 修改为:

private void someClassFunction()
{
  .....
  Phone phone = new Phone( company, "1115551234" );
  company.getPhoneSet().add( phone );
  this.phoneRespository.save( phone );  // <<<< NOTE THIS LINE
  System.out.println( "phone.id: " + phone.getId() );
}

然后调用 someClassFunction() 我得到:

phone.id: 47

我可以立即使用分配给 id 的数据库。

我没有发现任何在线文档或教程中公开的 parent/child 持续(即:this.companyRespository.save(公司))行为。我被引导相信从 parent 坚持应该与直接坚持 child 一样工作(即:this.phoneRespository.save(phone)).

我是不是做错了什么?我的实体定义不正确吗?

是的,这是预期的 - 检查您的 'save' 方法上的合同。它 returns 一个实例,可能是您传入的实例的副本,您需要检查和使用的正是这个实例 - 当 entityManager 与数据库同步时(在事务提交时),它将设置其标识,或者如果 EntityManager 被刷新)。

  Phone phone = new Phone( company, "1115551234" );
  company.getPhoneSet().add( phone );
  phone.setCompany(company);//Don't forget to set this!
  Company mergedCompanyInstance = this.companyRespository.save( company );
  Phone managedPhone = mergedCompanyInstance.getPhoneSet().get(0);//assuming you have only one in the set, otherwise, check by phone number.
  System.out.println( "phone.id: " + phone.getId() );
  System.out.println( "managedPhone.id: " + managedPhone.getId() );

Spring 在保存方法中进行一些内部检查以确定它是否应该调用 JPA EntityManager merge 或 persist api。如果它调用 merge,它 returns 来自上下文的托管实体实例(可能是您提供的实例的克隆),而如果它调用 persist,它会获取您的实例并使其成为托管实体。它是在任何 findById 和查询方法上返回的托管实例。