Spring 数据 Jpa:来自 parent 个实体的 child 个实体不会更新 child 个身份
Spring Data Jpa: persisting child entities from parent entity does not update child identity
环境:
- OS:Ubuntu 20.04 LTS
- Java:OpenJDK 17.0.3
- Spring 开机:2.6.7
- MySQL: 8.0.29
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 和查询方法上返回的托管实例。
环境:
- OS:Ubuntu 20.04 LTS
- Java:OpenJDK 17.0.3
- Spring 开机:2.6.7
- MySQL: 8.0.29
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 和查询方法上返回的托管实例。