[英]Spring boot JPA OneToMany relationship - create related object if not exist
假設我在Person
和Job
之間有 oneToMany 關系。 每個人只有一份工作,而一份工作有很多人。
我有一個 controller 調用服務,該服務調用將執行查詢的存儲庫。
他們來了:
@RestController
@CrossOrigin()
@RequestMapping(path = "api/person")
public class PersonController {
private final PersonService personService;
@Autowired
public PersonController(PersonService personService) {
this.personService = personService;
}
@PostMapping
public Person storePerson(@RequestBody Person person) {
return this.personService.storePerson(person);
}
//...more code is also here
}
@Service
public class PersonService {
private final PersonRepository personRepository;
@Autowired
public PersonService(PersonRepository personRepository, CountryRepository countryRepository,
JobRepository jobRepository, RoleRepository roleRepository, HairColorRepository hairColorRepository) {
this.personRepository = personRepository;
}
public Person storePerson(Person person) {
return this.personRepository.save(person);
}
//...more code is also here
}
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}
現在模型和我定義它們之間關系的方式。 我可以通過兩種方式對此進行編碼。
情景 1:
@Entity
@Table(name = "people")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = Job.class)
@JoinColumn(name = "job_id")
private Job job;
// ...getters and setters, constructors, toString(), etc are here
}
@Entity
@Table(name = "jobs")
public class Job {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@OneToMany(mappedBy = "job", orphanRemoval = true, cascade = CascadeType.ALL)
private Set<Person> persons;
// ...getters and setters, constructors, toString(), etc are here
}
我使用 postman 將記錄插入此數據庫。 我發送一個POST
請求,這是正文:
第一個 Json
{
"name": "James",
"job": {
"id": null,
"name": "Doctor"
}
}
這很完美,因為它創建了這個人,它還創建了一個在數據庫中不存在的新工作,並且還創建了兩者之間的關系。 但是根據第二個請求,我想重用該作業。 所以我提出這個要求:
第二個Json
{
"name": "David",
"job": {
"id": 1,
"name": "Doctor"
}
}
在這里我得到一個例外:
{
"timestamp": "2022-08-05T11:20:41.037+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "detached entity passed to persist: ir.arm.archiver.job.Job; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: ir.arm.archiver.job.Job",
"path": "/api/person"
}
Senario2
如果我稍微更改關系注釋中的Cascade
值,我會得到完全相反的結果。 如果在Person.java
中,我將private Job job
字段的注釋更改為使用Cascade.MERGE
,如下所示:
@ManyToOne(cascade = CascadeType.MERGE, fetch = FetchType.EAGER, targetEntity = Job.class)
@JoinColumn(name = "job_id")
private Job job;
然后,當我通過第一個 Json時,這一次,我得到一個異常:
{
"timestamp": "2022-08-05T11:36:17.854+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : ir.arm.archiver.person.Person.job -> ir.arm.archiver.job.Job; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : ir.arm.archiver.person.Person.job -> ir.arm.archiver.job.Job",
"path": "/api/person"
}
但是,如果我自己在數據庫中創建工作記錄,然后使用第二個 Json執行請求,它將起作用,並創建與現有工作記錄有關系的人。
現在我的問題是:
我怎樣才能將兩者結合起來? 我希望 JPA 兩者都做。 有什么辦法可以同時傳遞 jsons 和 jpa 自動創建作業,如果Id
是 null,如果它有Id
則獲取並重用它?
我找到了解決辦法。 移除 Person Entity 的 Job 成員變量的cascade
屬性。 JPA 將兩者結合起來。
更新人員實體:
@Entity
@Table(name = "people")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(fetch = FetchType.EAGER, targetEntity = Job.class)
@JoinColumn(name = "job_id")
private Job job;
// ...getters and setters, constructors, toString(), etc are here
}
Output(在數據庫人員表中):
工作表:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.