Spring JPA嵌套异常:已分离的实体传递给持久化

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

我尝试了在SO和其他网站上找到的关于与Hibernate建立一对一关系的教程

所以,我有两个模型,这里是最后的修改,比如我在之前的测试中删除的@MapsId注释

乌萨里奥:

@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);

    }