entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

1voto

JPA @ManyToMany Tabla intermedia con más valores que FKs

¡Saludos!

Estoy haciendo un Backend (Spring Boot, JPA) y mi problema es el siguiente:

Tablas

  • Empleado
  • Equipo_Empleado
  • Equipo

Como se pueden dar cuenta hay una relación en Empleado - Equipo de Muchos a Muchos (Necesito llevar un historial) y mi tabla Equipo_Empleado quiero utilizarla para tener no sólo los FK, sino tengo datos extras, FechaAlta, FechaBaja, Comentario_Alta, Comentario_Baja.

Pongo mis Modelos:

Empleado:

@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Table(name = "Empleado")
public class Empleado {

    @Column(name = "PK_Empleado", insertable = false, updatable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer idEmpleado;

    @OneToOne
    @JoinColumn(name = "FK01_Unidad", nullable = false)
    private Caracteristica red;

    @Column(name = "Nombre", nullable = false, length = 100, insertable = true, updatable = true)
    private String nombre;

    @Column(name = "Apellido_Paterno", nullable = false, length = 100, insertable = true, updatable = true)
    private String apellidoPaterno;

    @Column(name = "Apellido_Materno", nullable = true, length = 100, insertable = true, updatable = true)
    private String apellidoMaterno;

    @Column(name = "Usuario", nullable = false, length = 50, insertable = true, updatable = true)
    private String usuario;

    @Column(name = "Num_Empleado", nullable = false, length = 50, insertable = true, updatable = true)
    private String numEmpleado;

    @Column(name = "Fecha_Sistema", nullable = false, insertable = false, updatable = false)
    @JsonFormat(pattern="MM/dd/YYYY")
    private Date fechaSistema;

    @Column(name = "Fecha_Alta", nullable = false, insertable = true, updatable = true)
    @JsonDeserialize(using = DateAndTime.class)
    @JsonFormat(pattern="MM/dd/YYYY")
    private Date fechaAlta;

    @Column(name = "Fecha_Baja", nullable = true, insertable = true, updatable = true)
    @JsonDeserialize(using = DateAndTime.class)
    @JsonFormat(pattern="MM/dd/YYYY")
    private Date fechaBaja;

    @Column(name = "Habilitado", nullable = false, length = 1, insertable = true, updatable = true)
    private Integer habilitado;

    @ManyToMany(cascade = {
        CascadeType.PERSIST,
        CascadeType.MERGE
    })
    @JoinTable(
        name = "Equipo_Empleado",
        joinColumns = @JoinColumn(name = "FK01_Equipo", nullable = false),
        inverseJoinColumns = @JoinColumn(name = "FK02_Empleado", nullable = false) )
    private Set<Equipo> lstEquipos = new HashSet<>();

    public void addEquipo(Equipo equipo) {
        if (this.lstEquipos == null) {
            this.lstEquipos = new HashSet<>();
        }
        this.lstEquipos.add(equipo);
    }

    public void removeEquipo(Equipo equipo) {
        lstEquipos.remove(equipo);
        equipo.getLstEmpleado().remove(this);
    }
        /* SETTERS AND GETTERS*/
}

Equipo:

@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Table(name = "Equipo")
public class Equipo {

    @Column(name = "PK_Equipo", insertable = false, updatable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer idEquipo;

    @OneToOne
    @JoinColumn(name = "FK01_Propietario", nullable = false)
    private Caracteristica contrato;

    @OneToOne
    @JoinColumn(name = "FK02_Unidad", nullable = false)
    private Caracteristica red;

    @OneToOne
    @JoinColumn(name = "FK03_Zona", nullable = false)
    private Caracteristica zona;

    @OneToOne
    @JoinColumn(name = "FK04_Subzona", nullable = true)
    private Caracteristica subzona;

    @OneToOne
    @JoinColumn(name = "FK05_Area", nullable = true)
    private Caracteristica area;

    @OneToOne
    @JoinColumn(name = "FK06_Marca", nullable = true)
    private Caracteristica marca;

    @OneToOne
    @JoinColumn(name = "FK07_Estado", nullable = false)
    private Caracteristica estado;

    @OneToOne
    @JoinColumn(name = "FK08_Tipo", nullable = false)
    private Caracteristica tipo;

    @Column(name = "Fecha_Sistema", nullable = false, insertable = false, updatable = false)
    @JsonFormat(pattern="MM/dd/YYYY")
    private Date fechaSistema;

    @Column(name = "Fecha_Alta", nullable = false, insertable = true, updatable = true)
    @JsonDeserialize(using = DateAndTime.class)
    @JsonFormat(pattern="MM/dd/YYYY")
    private Date fechaAlta;

    @Column(name = "Fecha_Baja", nullable = true, insertable = true, updatable = true)
    @JsonDeserialize(using = DateAndTime.class)
    @JsonFormat(pattern="MM/dd/YYYY")
    private Date fechaBaja;

    @Column(name = "Modelo", nullable = false, length = 100, insertable = true, updatable = true)
    private String modelo;

    @Column(name = "Serie", nullable = false, length = 100, insertable = true, updatable = true)
    private String serie;

    @Column(name = "ID", nullable = false, insertable = true, updatable = true)
    private Integer id;

    @Column(name = "Folio", nullable = false, length = 100, insertable = true, updatable = true)
    private String folio;

    @Column(name = "Costo", scale = 8, nullable = false, length = 100, insertable = true, updatable = true)
    private double costo;

    @Column(name = "Descripcion", nullable = false, length = 300, insertable = true, updatable = true)
    private String descripcion;

    @Column(name = "Arrendada", nullable = false, length = 1, insertable = true, updatable = true)
    private Integer arrendada;

    @Column(name = "Activo", nullable = false, length = 1, insertable = true, updatable = true)
    private Integer activo;

    @Column(name = "Habilitado", nullable = false, length = 1, insertable = true, updatable = true)
    private Integer habilitado;

    @ManyToMany(mappedBy = "lstEquipos")
    private Set<Empleado> lstEmpleado = new HashSet<>();

       /* SETTERS AND GETTERS*/
}

Recurso

@RestController
@RequestMapping("/empleado")
public class EmpleadoRecurso {

    @Autowired
    private EmpleadoService empleadoService;

    @RequestMapping(
            value = "/guardarEmpleado",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE
    )
    public Empleado guardarEmpleado(@RequestBody Empleado empleado) {
        return empleadoService.guardarEmpleado(empleado);
    }
}

Servicio:


@Service
public class EmpleadoService {

    @Autowired
    private EmpleadoDAO empleadoDAO;

    public Empleado guardarEmpleado(Empleado empleado) {
        try {
            empleado = empleadoDAO.save(empleado);
            return empleado;
        } catch (Exception e) {
            e.printStackTrace();
            return new Empleado();
        }
    }
}

Persistencia:

public interface EmpleadoDAO extends JpaRepository<Empleado, Integer> {
}

Funciona cuando a mi tabla Equipo_Empleado tiene que acepta NULL los los campos de fechas y comentarios, porque obviamente no van en la inserción que hace JPA, pero no sé como incluirlos, claro, podría hacer que actualice los campos después de crearlos, pero he estado buscando una forma de hacerlo en un solo paso.
Ya busqué mucha documentación de JPA y @ManyToMany, pero nada, lo único que indican es insertar FKs, o ¿está mal cómo lo he pensado? Es una mala práctica?

1 Respuesta

1voto

Th3Mik3s Puntos2950

Saludos, aquí pongo la forma en la que lo solucioné, puede que no sea la más adecuada, pero hasta ahorita es lo que mejor me funciona...

Tabla Empleado

@OneToMany(mappedBy = "empleado")//Hace referencia al campo de Empleado_Equipo
private List<EmpleadoEquipo> lstEquipos;

Tabla Empleado_Equipo

@ManyToOne
@JsonBackReference//Indico que es la referencia de retorno(evitando ciclo infinito)
@JoinColumn(name = "FK01_Empleado", insertable = true, nullable = false, updatable = false)
private Empleado empleado;

@ManyToOne
@JsonBackReference// Indico que es la referencia de retorno(evitando ciclo infinito)
@JoinColumn(name = "FK02_Equipo", insertable = true, nullable = false, updatable = false)
private Equipo equipo;

/*Indica que no es parte de la tabla en la base de datos
y lo ocupo para tener el idEmpleado/idEquipo*/
@Transient
private Integer idEmpleado;

@Transient
private Integer idEquipo;

Tabla Equipo

@OneToMany(mappedBy = "equipo")//Hace referencia al campo de Empleado_Equipo
private List<EmpleadoEquipo> lstEmpleados;

Dejo mis 3 clases y dejaré la pregunta abierta por si en un futuro agrego mejoras al código.
(Setters, Getters, HashCode y Equal son omitidos, también quite campos para que no sean tan largas las clases)

import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Table(name = "Empleado")
public class Empleado {

  @Column(name = "PK_Empleado", insertable = false, updatable = false)
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Integer idEmpleado;

  @OneToOne
  @JoinColumn(name = "FK01_Unidad", nullable = false)
  private Caracteristica red;

  @Column(name = "Nombre", nullable = false, length = 100, insertable = true, updatable = true)
  private String nombre;

  @Column(name = "Fecha_Sistema", nullable = false, insertable = false, updatable = false)
  @JsonFormat(pattern = "MM/dd/YYYY")
  private Date fechaSistema;

  @Column(name = "Fecha_Alta", nullable = false, insertable = true, updatable = true)
  @JsonDeserialize(using = DateAndTime.class)
  @JsonFormat(pattern = "MM/dd/YYYY")
  private Date fechaAlta;

  @Column(name = "Habilitado", nullable = false, length = 1, insertable = true, updatable = true)
  private Integer habilitado;

  @OneToMany(mappedBy = "empleado")
  private List<EmpleadoEquipo> lstEquipos;
}

Tabla Empleado_Equipo

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@Entity
@Table(name = "EMPLEADO_EQUIPO")
public class EmpleadoEquipo {

  @Column(name = "PK_EMPLEADO_EQUIPO", insertable = false, updatable = false)
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer idEmpleadoEquipo;

  @ManyToOne
  @JsonBackReference
  @JoinColumn(name = "FK01_Empleado", insertable = true, nullable = false, updatable = false)
  private Empleado empleado;

  @ManyToOne
  @JsonBackReference
  @JoinColumn(name = "FK02_Equipo", insertable = true, nullable = false, updatable = false)
  private Equipo equipo;

  @Column(name = "FECHA_SISTEMA", nullable = false, insertable = false, updatable = false)
  @JsonFormat(pattern = "MM/dd/YYYY")
  private Date fechaSistema;

  @Column(name = "FECHA_ALTA", nullable = false, insertable = true, updatable = true)
  @JsonDeserialize(using = DateAndTime.class)
  @JsonFormat(pattern = "MM/dd/YYYY")
  private Date fechaAlta;

  @Column(name = "COMENTARIOS_ALTA", nullable = false, insertable = true, updatable = true)
  private String comentariosAlta;

  @Column(name = "HABILITADO", nullable = false, length = 1, insertable = true, updatable = true)
  private Integer habilitado;

  @Transient
  private Integer idEmpleado;

  @Transient
  private Integer idEquipo;
}

Tabla Equipo

import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@Entity
@Table(name = "Equipo")
public class Equipo {

  @Column(name = "PK_Equipo", insertable = false, updatable = false)
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Integer idEquipo;

  @OneToOne
  @JoinColumn(name = "FK01_Propietario", nullable = false)
  private Caracteristica contrato;

  @OneToOne
  @JoinColumn(name = "FK02_Unidad", nullable = false)
  private Caracteristica red;

  @Column(name = "Fecha_Sistema", nullable = false, insertable = false, updatable = false)
  @JsonFormat(pattern = "MM/dd/YYYY")
  private Date fechaSistema;

  @Column(name = "Fecha_Alta", nullable = false, insertable = true, updatable = true)
  @JsonDeserialize(using = DateAndTime.class)
  @JsonFormat(pattern = "MM/dd/YYYY")
  private Date fechaAlta;

  @Column(name = "Habilitado", nullable = false, length = 1, insertable = true, updatable = true)
  private Integer habilitado;

  @OneToMany(mappedBy = "equipo")
  private List<EmpleadoEquipo> lstEmpleados;
}

0voto

Peter comentado

Gracias por compartirlo.

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta