¿Alguien puede explicarme @MapsId en hibernación?

Respuestas:

47

Aquí hay una buena explicación de Object DB .

Designa un atributo de relación ManyToOne o OneToOne que proporciona la asignación para una clave principal EmbeddedId, un atributo dentro de una clave principal EmbeddedId o una clave principal simple de la entidad principal. El elemento de valor especifica el atributo dentro de una clave compuesta al que corresponde el atributo de relación. Si la clave principal de la entidad es del mismo tipo de Java que la clave principal de la entidad a la que hace referencia la relación, no se especifica el atributo de valor.

// parent entity has simple primary key

@Entity
public class Employee {
   @Id long empId;
   String name;
   ...
} 

// dependent entity uses EmbeddedId for composite key

@Embeddable
public class DependentId {
   String name;
   long empid;   // corresponds to primary key type of Employee
}

@Entity
public class Dependent {
   @EmbeddedId DependentId id;
    ...
   @MapsId("empid")  //  maps the empid attribute of embedded id
   @ManyToOne Employee emp;
}

Lea los documentos de API aquí.

ManuPK
fuente
6
Pero, ¿qué tiene de bueno? Incluso sin @MapsId, uno puede usar JoinColumn para el mismo efecto, ¿no es así? Y si es así, este ejemplo no dice realmente para qué sirve esta anotación.
Maksim Gumerov
2
Dado que ambas entidades compartirán la misma clave principal, la entidad con una columna designada por @MapsIdtendrá en la capa de persistencia (base de datos) solo la columna de clave principal. La idea es compartir la clave principal entre las dos entidades.
johanwannheden
¿Qué es una clave primaria EmbeddedId? ¿En qué se diferencia de la clave principal normal?
sofs1
"El elemento de valor especifica el atributo dentro de una clave compuesta a la que corresponde el atributo de relación". 1) ¿Qué se entiende por elemento de valor? Por favor, dé un ejemplo. 2) ¿Qué es una clave compuesta? 3) ¿Cuál es el atributo de relación y da un ejemplo?
sofs1
@MaksimGumerov es eficiente porque puede buscar Dependentsimplemente conociendo el identificador de Employee.
Emmanuel Osimosu
26

Encontré esta nota también útil: @MapsIden la anotación de hibernación mapea una columna con la columna de otra tabla.

También se puede utilizar para compartir la misma clave primaria entre 2 tablas.

Ejemplo:

@Entity
@Table(name = "TRANSACTION_CANCEL")
public class CancelledTransaction {
    @Id
    private Long id; // the value in this pk will be the same as the
                     // transaction line from transaction table to which 
                     // this cancelled transaction is related

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_TRANSACTION", nullable = false)
    @MapsId
    private Transaction transaction;
    ....
}

@Entity
@Table(name = "TRANSACTION")
@SequenceGenerator(name = "SQ_TRAN_ID", sequenceName = "SQ_TRAN_ID")
public class Transaction  {
    @Id
    @GeneratedValue(generator = "SQ_TRAN_ID", strategy = GenerationType.SEQUENCE)
    @Column(name = "ID_TRANSACTION", nullable = false)
    private Long id;
    ...
}
Tónico
fuente
¿Dónde pongo @MapsId en una asociación bidireccional? Deberían tener ambas clases @MapsId. ¿Incluso hace alguna diferencia?
marcus
Creo que una mesa será el "propietario" del pk original (la que tiene @Idy @GeneratedValuey @Column) y tendrá un @OneToOney @JoinColumncon la otra mesa, y la otra mesa tendrá el @MapsId. Sin embargo, esto probablemente no funcionaría si primero quisiera INSERTAR en la "otra tabla".
Tonsic
1
Un buen artículo sobre esta forma de uso (usando la identificación de otra tabla como identificación de otra entidad) está aquí vladmihalcea.com/…
Lubo
Pero si desea filtrar las transacciones de las canceladas ... lo cual es una causa común. ¿Cómo es esto más eficiente? Quiero decir, para SQL, solo tiene que decir NOT NULL para TRANSACTION.fk_cancelled_id pero en este caso, habrá más operaciones.
L_F
En este caso específico aquí, es común usar una columna como 'tipo' en la clase base y la tabla, donde identificaría si la transacción es del tipo 'cancelar' u otro.
Tonsic
3

Como explicó Vladimir en su tutorial , la mejor manera de mapear una relación @OneToOne es usar @MapsId. De esta manera, ni siquiera necesita una asociación bidireccional, ya que siempre puede obtener la entidad secundaria utilizando el identificador de la entidad principal.

BERGUIGA Mohamed Amine
fuente
2

MapsId le permite usar la misma clave principal entre dos entidades / tablas diferentes. Nota: cuando usa MapsId, la CASCADE.ALLbandera se vuelve inútil y deberá asegurarse de que sus entidades se guarden manualmente.

Janac Meena
fuente
1

En mi humilde opinión, la mejor manera de pensar @MapsId es cuando necesita mapear una clave compuesta en una entidad: m.

Por ejemplo, un cliente puede tener uno o más consultores y un consultor puede tener uno o más clientes:

ingrese la descripción de la imagen aquí

Y sus entradas serían algo como esto (pseudo código Java):

@Entity
public class Customer {
   @Id
   private Integer id;

   private String name;
}

@Entity
public class Consultant {
   @Id
   private Integer id;

   private String name;

   @OneToMany
   private List<CustomerByConsultant> customerByConsultants = new ArrayList<>();

   public void add(CustomerByConsultant cbc) {
      cbc.setConsultant(this);
      this.customerByConsultant.add(cbc);
   }
}

@Embeddable
public class ConsultantByConsultantPk implements Serializable {

    private Integer customerId;

    private Integer consultantId;
}

@Entity
public class ConsultantByConsultant {

   @EmbeddedId
   private ConsultantByConsultantPk id = new ConsultantByConsultantPk();

   @MapsId("customerId")
   @JoinColumn(insertable = false, updatable = false)
   Customer customer;

   @MapsId("consultantId")
   @JoinColumn(insertable = false, updatable = false)
   Consultant consultant;
}

Al mapear de esta manera, JPA inserta Customere Consultantidentifica automáticamente en el EmbeddableIdcada vez que guarda un consultor. Por lo tanto, no es necesario crear manualmente el archivo ConsultantByConsultantPk.

Jaumzera
fuente