Spring JPA嵌套异常:已分离的实体传递给持久化
我尝试了在SO和其他网站上找到的关于与Hibernate建立一对一关系的教程 所以,我有两个模型,这里是最后的修改,比如我在之前的测试中删除的@MapsId注释 乌萨里奥:Spring JPA嵌套异常:已分离的实体传递给持久化,spring,hibernate,jpa,Spring,Hibernate,Jpa,我尝试了在SO和其他网站上找到的关于与Hibernate建立一对一关系的教程 所以,我有两个模型,这里是最后的修改,比如我在之前的测试中删除的@MapsId注释 乌萨里奥: @Entity @Table(name="usuarios") @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class Usuar
@Entity
@Table(name="usuarios")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Usuario {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="usuarios_id_seq")
@SequenceGenerator(name="usuarios_id_seq", sequenceName="usuarios_id_seq", allocationSize=1)
@Column(name="id")
private Long id;
@ManyToOne
@JoinTable(name="roles_usuarios", joinColumns={@JoinColumn(name="usuarios_id", referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="roles_id", referencedColumnName="id")})
private Rol rol;
@OneToOne(cascade = CascadeType.ALL, mappedBy="usuario")
private Cliente cliente;
客户:
@Entity
@Table(name="clientes")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Cliente {
@Id
//@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="clientes_id_seq")
//@SequenceGenerator(name="clientes_id_seq", sequenceName="clientes_id_seq", allocationSize=1)
//@Column(name="id")
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="usuario_id", referencedColumnName="id")
@MapsId
private Usuario usuario;
客户控制员:
@PostMapping("/")
public ResponseEntity<Void> postCliente(@RequestBody Cliente cliente, UriComponentsBuilder ucBuilder) {
if( clienteService.isClienteExist(cliente) ){
return new ResponseEntity<Void>(HttpStatus.CONFLICT);
}
clienteService.save(cliente);
HttpHeaders headers = new HttpHeaders();
headers.setLocation( ucBuilder.path("/{id}").buildAndExpand(cliente.getId()).toUri() );
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
如果您注意到我也与Rol表有一种多对一的关系,这种关系很好,但是当我在OneTONE中传递信息时,我将其作为JSON传递,它会产生:分离实体传递给persist:com.swagos.entities.Usuario
IDK,如果我缺少一些注释,或者数据库是在运行spring应用程序时创建的。我提供了一个有点限定的猜测,因为您没有包含显示如何调用persist的代码 该错误意味着您要传递给persist()的Usuario实例已经有一个主键,但它不是该持久性上下文的托管实体,有关详细信息,请参见此处 我的猜测是,Usuario实例是由另一个EntityManager加载的,然后json序列化到前端,然后发布回后端,您需要在客户机上设置它(因为您在两个方向上进行了级联,它也可能是Usuario上设置的客户机)。每次在一个持久性上下文中加载一个实体,并且要在另一个持久性上下文中保存它时,必须调用
em.merge()
,或者必须调用em.find()
将其加载到其中(然后设置更改)
JPA不是魔术,实体的生命周期和管理它们的持久性上下文都有很好的定义,除非开发人员理解这些机制是如何工作的,否则在尝试使用框架时会浪费很多时间
此外,只有当客户使用@EmbeddedId作为主键时才应使用@MapsId,情况似乎并非如此。您能显示生成此异常的代码吗?我用代码更新了。。。如何调用保存…您是否将现有或新的Usuario作为控制器接收的客户的一部分发送。现有。。。我想我能做到。。。刚刚将级联类型更改为:cascade=CascadeType.MERGE,并删除您所说的@MapsId注释,谢谢。如果您通过将级联类型从“全部”随机更改为“合并”而成功,并且您认为这解决了您的问题,那么您真的需要阅读文档!您需要理解为什么会出现分离错误(为什么我会问我的问题),如果不了解这一点,问题几乎肯定会再次出现。我从2009年开始与JPA合作,相信我,在您了解实体生命周期之前,有很多错误您不会理解,您将在堆栈溢出上花费大量时间。我知道我知道。。。当然,我会阅读文档,但您提供的链接会指导我如何使用已删除的实体,因此我尝试了合并选项。我是JPA的新手,所以这很有帮助。。。thanx很多。代码失败的原因是,当客户端是新的,并且Usuario已经存在时,Usuario基本上是一个分离的实体(它是由不同的持久性上下文加载的)。由于您有级联持久化,保存客户机将导致保存被传播到Usuario,但由于它被分离,您会得到一个错误。将CascadeType从ALL更改为MERGE是有效的,因为这意味着persist不是级联的,但使用cascade NONE可能更正确。但更好的解决方案可能是将分离的实体合并/加载到当前的持久性上下文中。
@Override
public Cliente save(Cliente cliente) {
Cliente clt = new Cliente();
clt.setUsuario(cliente.getUsuario());
clt.setRazonSocial(cliente.getRazonSocial());
clt.setRfc(cliente.getRfc());
clt.setDireccion(cliente.getDireccion());
clt.setEmail(cliente.getEmail());
clt.setTelefono(cliente.getTelefono());
clt.setContacto(cliente.getContacto());
clt.setTelContacto(cliente.getTelContacto());
clt.setEmailContacto(cliente.getEmailContacto());
return clienteRepository.save(clt);
}