0

I have the next error when I'm in the frontEnd and I implement a create.This is only happens when I create a field in the table EmpleadoRol with the attributes "id_empleado_rol", "rol_Id" and "empleado_Id".

020-06-08 16:52:41.155  WARN 15382 --- [nio-8080-exec-9] o.h.a.i.UnresolvedEntityInsertActions    : HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.
    Unsaved transient entity: ([com.jamesferrer.consultorio.apirest.models.entity.Empleado#<null>])
    Dependent entities: ([[com.jamesferrer.consultorio.apirest.models.entity.EmpleadoRol#<null>]])
    Non-nullable association(s): ([com.jamesferrer.consultorio.apirest.models.entity.EmpleadoRol.empleado])

This is my entity Empleado:

@Entity
@Table(name="empleados")
public class Empleado implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id_empleado")
    private Integer idEmpleado;

    @Column(nullable=false)
    @NotEmpty(message = "no puede estar vacio.")
    @Size(min=3, max=50, message = "debe tener un tamaño entre 3 y 50 caracteres")
    private String nombre;

    ...

    @ManyToMany(fetch=FetchType.LAZY)
    @JoinTable(name="empleados_roles", joinColumns=@JoinColumn(name="empleado_Id"), 
    inverseJoinColumns=@JoinColumn(name="rol_Id"),
    uniqueConstraints= {@UniqueConstraint(columnNames={"empleado_Id", "rol_Id"})})
    private List<Rol> roles;

    @NotNull(message="el tipo de identificación no puede estar vacia.")
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="tipo_Identificacion_Id")
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    private TipoIdentificacion tipoIdentificacion;

    ...

This is my entity EmpleadoRol:

@Entity
@Table(name = "empleados_roles")
public class EmpleadoRol implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_empleado_rol")
    private Integer idEmpleadoRol;

    @NotNull(message="no puede estar vacio!")
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="rol_Id")
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    private Rol rol;

    @NotNull(message="no puede estar vacio!")
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="empleado_Id")
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    private Empleado empleado;

    ...

This is my IEmpleadoDao

@Repository
public interface IEmpleadoDao extends JpaRepository<Empleado, Integer>{

....

    @Query(value="SELECT nombre FROM(SELECT nombre FROM empleados e LEFT JOIN empleados_roles er ON e.id_empleado = er.empleado_Id WHERE nombre like %?1% GROUP BY nombre HAVING count(empleado_Id) <= 1) val", nativeQuery=true)
     <T> List<T> findNotRepeatEmpleado(String term1, Class<T> type);

}

This is my controller:

@RestController
@RequestMapping("/api")
public class EmpleadoRolRestController {

...

@Secured("ROLE_ADMIN")
    @PostMapping("/perfiles")
    public ResponseEntity<?> create(@Valid @RequestBody EmpleadoRol empleadoRol, BindingResult result){

        EmpleadoRol empleadoRolNew = null;
        Map<String, Object> response = new HashMap<>();

        if (result.hasErrors()) {
            List<String> errors = result.getFieldErrors()
                    .stream()
                    .map(err -> "El campo '" + err.getField() + "' " + err.getDefaultMessage())
                    .collect(Collectors.toList());

            response.put("errors", errors);
            return new ResponseEntity<Map<String, Object>>(response, HttpStatus.BAD_REQUEST);
        }

        try {

            empleadoRolNew = empleadoRolService.save(empleadoRol);

        } catch(DataAccessException e) {
            response.put("mensaje", "Error al crear el registro en la base de datos");
            response.put("error", e.getMessage().concat(": ").concat(e.getMostSpecificCause().getMessage()));
            return new ResponseEntity<Map<String, Object>>(response, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        response.put("mensaje", "El perfil ha sido asignado con éxito!");
        response.put("empleadoRol", empleadoRolNew);
        return new ResponseEntity<Map<String, Object>>(response, HttpStatus.CREATED);
    }

@Secured("ROLE_ADMIN")
    @GetMapping("/perfiles/filtrar-empleados/{term1}")
    public List<EmpleadoNombre> filtrarEmpleados(@PathVariable String term1){

        return empleadoService.findNotRepeatEmpleado(term1, EmpleadoNombre.class);
    }

I hope that someone can help me. Thanks!

James
  • 77
  • 6

1 Answers1

0

Your answer is really in the exception.

You are saving a EmpleadoRol in the line

empleadoRolNew = empleadoRolService.save(empleadoRol);

This entity references an entity of type Empleado with this attribute:

@NotNull(message="no puede estar vacio!")
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="empleado_Id")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private Empleado empleado;

And that entity is transient, i.e. it is not attached to a persistence context.

You can fix this by either adding a cascade attribute to @ManyToOne as discussed in the question https://stackoverflow.com/a/13027444/66686

Alternatively you need to save the Empleado first.

I'd prefer the second variant since if one applies the patterns of Domain Driven Design the two are separate aggregates and therefore should be handled by separate repositories.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348