La propiedad no nula hace referencia a un valor transitorio: la instancia transitoria debe guardarse antes de la operación actual

5 minutos de lectura

Tengo 2 modelos de dominio y un controlador Spring REST como se muestra a continuación:

@Entity
public class Customer{

@Id
private Long id;

@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name="COUNTRY_ID", nullable=false)
private Country country;

// other stuff with getters/setters

}

@Entity
public class Country{

@Id
@Column(name="COUNTRY_ID")
private Integer id;

// other stuff with getters/setters

}

Controlador de descanso de primavera:

@Controller
@RequestMapping("/shop/services/customers")
public class CustomerRESTController {

   /**
    * Create new customer
    */
    @RequestMapping( method=RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    public com.salesmanager.web.entity.customer.Customer createCustomer(@Valid @RequestBody   Customer customer, Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {

        customerService.saveOrUpdate(customer);

        return customer;
    }

    // other stuff
}

Estoy tratando de llamar al servicio REST anterior con JSON a continuación como cuerpo:

{
    "firstname": "Tapas",
    "lastname": "Jena",
    "city": "Hyderabad",
    "country": "1"
}

Donde el código de país 1 ya está en la tabla de países. El problema es cuando llamo a este servicio y obtengo el siguiente error:

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.test.model.Customer.country -> com.test.model.Country; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.test.model.Customer.country -> com.test.model.Country

¡Cualquier ayuda será apreciada!

Avatar de usuario de Raju Rudru
Raju Rudru

Intenta poner CascadeType.ALL

@OneToOne(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name="COUNTRY_ID", nullable=false) 

private Country country;

  • Bien, entonces haz una cosa. Su objeto de cliente tiene un objeto de país con id 1. Pero ese objeto de país no está en estado de persistencia. Primero obtenga el objeto del país enviando la identificación del país. Establezca el objeto de país recuperado de la base de datos en el objeto Cliente. Luego guarde el objeto del cliente. Espero que esta vez no dé ningún error.

    – Raju Rudru

    29 de septiembre de 2013 a las 6:29

  • Extrañamente, CascadeType.ALL funciona para mí cuando esto no funciona: @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })

    – Sam Barnum

    27 de noviembre de 2019 a las 12:02

avatar de usuario de djejaquino
djejaquino

Tuve un problema similar. Dos entidades: Documento y Estado.
Documento tenía una relación OneToMany con Estadoque representó la historia de Estado la Documento tenido.

Entonces, hubo un @NotNull @ManyToOne referencia de Documento en el interior Estado.

Además, necesitaba saber el verdadero Estado de Documento. Entonces, necesitaba otra relación, esta vez @OneToOneademás @NotNullen el interior Documento.

El problema era: ¿cómo puedo persistir ambas entidades la primera vez si ambas tenían un @NotNull referencia al otro?

La solución fue: quitar @NotNull referencia de actualStatus referencia. De esta manera, pudo persistir ambas entidades.

  • Esto realmente no responde la pregunta. Si tiene una pregunta diferente, puede hacerla haciendo clic en Preguntar. También puede agregar una recompensa para llamar más la atención sobre esta pregunta una vez que tenga suficiente reputación.

    – skolima

    11/09/2014 a las 20:44

  • Presenté una solución a mi problema que era similar. Nada que ver con una nueva pregunta.

    – djejaquino

    14/11/2014 a las 13:55

Solo para agregar un escenario adicional que me llevó exactamente al mismo error:

Asegúrese de que las referencias anteriores que puedan existir no sean nulas.

Específicamente en mi caso, estaba usando Mapstruct para actualizar algunos campos de la entidad, por ejemplo

MyClass newInstance = //...
MyClass dbInstance = repository.findByField(someField);
MyClassMapper.MAPPER.update(dbInstance, newInstance);
repository.save(dbInstance);

Y mi mala implementación de MyClassMapper condujo a las referencias hacia atrás de dbInstance campos a configurar null cuando deberían estar apuntando hacia atrás dbInstance.

Recibí el mismo error y así es como lo resolví:

1ª Entidad:

    @Entity
    public class Person implements Serializable{
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int personId;
        private String name;
        private String email;
        private long phoneNumber;
        private String password;
        private String userType;
        @OneToOne(fetch = FetchType.LAZY, mappedBy = "personCustomer", cascade 
        = CascadeType.ALL)
        private Customer customer;

2ª Entidad:

@Entity
public class Customer implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int customerId;
    @OneToOne(fetch = FetchType.LAZY, optional = false, cascade = 
    CascadeType.ALL)
    @JoinColumn(name = "person_customer")
    @JsonIgnore
    private Person personCustomer;

Mi controlador:

@PostMapping("/customer/registration")
    public PersonCustomer addCustomer(@RequestBody Person person)
    {
        Customer customer = new Customer(person);
        person.setCustomer(customer);
        Customer cust = customerRepo.save(customer);
        logger.info("{}", cust);
        Optional<Person> person_Cust = 
        personRepo.findById(cust.getPersonCustomer().getPersonId());
        Person personNew = person_Cust.get();
        PersonCustomer personCust = new PersonCustomer();

        if(cust.equals(null))
        {   
            personCust.setStatus("FAIL");
            personCust.setMessage("Registration failed");
            personCust.setTimestamp(personCust.timeStamp());
        }
        personCust.setStatus("OK");
        personCust.setMessage("Registration OK");
        personCust.setTimestamp(personCust.timeStamp());
        personCust.setPerson(personNew);

        return personCust;
    }

El problema se resolvió cuando agregué “person.setCustomer(customer);”. Como ambas clases POJO tienen referencias mutuas, tenemos que “establecer” la referencia mutua antes de usar el método de repositorio JPA (customerRepo.save (customer));

Avatar de usuario de Péter Márkus
Peter Markus

Tuve exactamente el mismo problema. La solución parece ser enviar el JSON así:

{
  "firstname": "Tapas",
  "lastname": "Jena",
  "city": "Hyderabad",
  "country": {"id":"1"}
}

Supongo @RequestBody trata de mapear una entidad, no un solo campo ya que el Cliente instancia está haciendo referencia a un País instancia.

(Tengo dos entidades unidas de manera similar. En la base de datos, los registros para la entidad a la que se hace referencia (País en su caso) ya se crearon, pero la creación de la entidad (Cliente en su caso) con un json proporcionó el mismo mensaje de error. Para mí CascadeType .ALL no ayudó, pero el cambio escrito anteriormente en el JSON resolvió el problema. Para configuraciones adicionales, por supuesto, se puede considerar CascadeType).

Avatar de usuario de Miladesnovakaina
miladesnovakaina

deberías cambiar:

@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name="COUNTRY_ID", nullable=false)
private Country country;

a :

@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name="COUNTRY_ID")
private Country country;

simplemente elimine la configuración anulable.

¿Ha sido útil esta solución?