假设我在Person
和Job
之间有一个一对多关系,每个人只有一个作业,而一个作业有很多人。
我有一个控制器,它调用服务,服务调用将执行查询的存储库。
它们是:
@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> {
}
现在是模型和我定义它们之间关系的方式。我可以用两种方式来编码。
第一章:
@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"
}
塞纳里奥2
如果我稍微改变关系注解中的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;
然后,当我传递 First 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"
}
但是,如果我自己在数据库中创建了工作记录,然后用 Second Json 执行请求,它将工作,并创建与现有工作记录有关系的人员。
现在我的问题是:
我如何将两者结合起来?我希望JPA两者都能做到。有没有什么方法,能够传递两个jsons,并且如果Id
为空,JPA会自动创建作业,如果它有Id
,则获取并重用它?
1条答案
按热度按时间v8wbuo2f1#
我找到了修复程序。删除个人实体的Job成员变量的
cascade
属性。JPA将两者结合起来,并重用数据库中的现有作业。更新人员实体:
输出(在数据库人员表中):
作业表: