tutorial example ejemplos java hibernate jpa

java - example - En una asociación bidireccional JPA OneToMany/ManyToOne, ¿qué se entiende por "el lado inverso de la asociación"?



jpa java (5)

En estos ejemplos en TopLink JPA Annotation Reference :

Ejemplo 1-59 @OneToMany - Clase de cliente con genéricos

@Entity public class Customer implements Serializable { ... @OneToMany(cascade=ALL, mappedBy="customer") public Set<Order> getOrders() { return orders; } ... }

Ejemplo 1-60 @ManyToOne - Ordenar clase con genéricos

@Entity public class Order implements Serializable { ... @ManyToOne @JoinColumn(name="CUST_ID", nullable=false) public Customer getCustomer() { return customer; } ... }

Me parece que la entidad Customer es el propietario de la asociación. Sin embargo, en la explicación del atributo mappedBy en el mismo documento, está escrito que:

si la relación es bidireccional, establezca el elemento mappedBy en el lado inverso (no propietario) de la asociación con el nombre del campo o propiedad que posee la relación como se muestra en el Ejemplo 1-60.

Sin embargo, si no me equivoco, parece que en el ejemplo, el mappedBy está realmente especificado en el lado propietario de la asociación, en lugar del lado no propietario.

Entonces mi pregunta es básicamente:

  1. En una asociación bidireccional (de uno a muchos / muchos a uno), ¿cuál de las entidades es el propietario? ¿Cómo podemos designar a One Side como propietario? ¿Cómo podemos designar al lado de Muchos como el dueño?

  2. ¿Qué se entiende por "el lado inverso de la asociación"? ¿Cómo podemos designar el lado uno como el inverso? ¿Cómo podemos designar al lado de Muchos como el inverso?


Increíblemente, en 3 años nadie ha respondido a su excelente pregunta con ejemplos de ambas maneras de mapear la relación.

Como lo mencionaron otros, el lado "propietario" contiene el puntero (clave externa) en la base de datos. Puede designar a cualquiera de los lados como propietario, sin embargo, si designa el lado Uno como propietario, la relación no será bidireccional (el lado inverso "muchos" no tendrá conocimiento de su "propietario"). Esto puede ser deseable para la encapsulación / acoplamiento flexible:

// "One" Customer owns the associated orders by storing them in a customer_orders join table public class Customer { @OneToMany(cascade = CascadeType.ALL) private List<Order> orders; } // if the Customer owns the orders using the customer_orders table, // Order has no knowledge of its Customer public class Order { // @ManyToOne annotation has no "mappedBy" attribute to link bidirectionally }

La única solución de mapeo bidireccional es que el lado "muchos" tenga su puntero al "uno", y use el atributo @OneToMany "mappedBy". Sin el atributo "mappedBy", Hibernate esperará una asignación doble (la base de datos tendría tanto la columna de unión como la tabla de unión, que es redundante (por lo general no deseable)).

// "One" Customer as the inverse side of the relationship public class Customer { @OneToMany(cascade = CascadeType.ALL, mappedBy = "customer") private List<Order> orders; } // "many" orders each own their pointer to a Customer public class Order { @ManyToOne private Customer customer; }


La entidad que tiene la tabla con la clave externa en la base de datos es la entidad propietaria y la otra tabla, a la que se apunta, es la entidad inversa.


Para dos Clientes y orden de Entity Classes, hibernate creará dos tablas.

Posibles casos:

  1. mappedBy no se usa en Customer.java y Order.java Class then->

    En el lado del cliente, se creará una nueva tabla [name = CUSTOMER_ORDER] que mantendrá el mapeo de CUSTOMER_ID y ORDER_ID. Estas son las claves principales de Customer y Order Tables. En el lado del pedido, se requiere una columna adicional para guardar la asignación de registros Customer_ID correspondiente.

  2. mappedBy se usa en Customer.java [Como se indica en la declaración del problema] Ahora no se crea la tabla adicional [CUSTOMER_ORDER]. Solo una columna en la Tabla de pedidos

  3. mappedby se utiliza en Order.java Ahora hibernate creará una tabla adicional. [name = CUSTOMER_ORDER] Order Table no tendrá columna adicional [Customer_ID] para mapeo.

Cualquier lado se puede hacer propietario de la relación. Pero es mejor elegir el lado xxxToOne.

Efecto de codificación -> Solo el lado propietario de la entidad puede cambiar el estado de la relación. En el siguiente ejemplo, la clase BoyFriend es propietaria de la relación. incluso si Girlfriend quiere separarse, no puede.

import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Table(name = "BoyFriend21") public class BoyFriend21 { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Boy_ID") @SequenceGenerator(name = "Boy_ID", sequenceName = "Boy_ID_SEQUENCER", initialValue = 10,allocationSize = 1) private Integer id; @Column(name = "BOY_NAME") private String name; @OneToOne(cascade = { CascadeType.ALL }) private GirlFriend21 girlFriend; public BoyFriend21(String name) { this.name = name; } public BoyFriend21() { } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BoyFriend21(String name, GirlFriend21 girlFriend) { this.name = name; this.girlFriend = girlFriend; } public GirlFriend21 getGirlFriend() { return girlFriend; } public void setGirlFriend(GirlFriend21 girlFriend) { this.girlFriend = girlFriend; } } import org.hibernate.annotations.*; import javax.persistence.*; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Table; import java.util.ArrayList; import java.util.List; @Entity @Table(name = "GirlFriend21") public class GirlFriend21 { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Girl_ID") @SequenceGenerator(name = "Girl_ID", sequenceName = "Girl_ID_SEQUENCER", initialValue = 10,allocationSize = 1) private Integer id; @Column(name = "GIRL_NAME") private String name; @OneToOne(cascade = {CascadeType.ALL},mappedBy = "girlFriend") private BoyFriend21 boyFriends = new BoyFriend21(); public GirlFriend21() { } public GirlFriend21(String name) { this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public GirlFriend21(String name, BoyFriend21 boyFriends) { this.name = name; this.boyFriends = boyFriends; } public BoyFriend21 getBoyFriends() { return boyFriends; } public void setBoyFriends(BoyFriend21 boyFriends) { this.boyFriends = boyFriends; } } import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import java.util.Arrays; public class Main578_DS { public static void main(String[] args) { final Configuration configuration = new Configuration(); try { configuration.configure("hibernate.cfg.xml"); } catch (HibernateException e) { throw new RuntimeException(e); } final SessionFactory sessionFactory = configuration.buildSessionFactory(); final Session session = sessionFactory.openSession(); session.beginTransaction(); final BoyFriend21 clinton = new BoyFriend21("Bill Clinton"); final GirlFriend21 monica = new GirlFriend21("monica lewinsky"); clinton.setGirlFriend(monica); session.save(clinton); session.getTransaction().commit(); session.close(); } } import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import java.util.List; public class Main578_Modify { public static void main(String[] args) { final Configuration configuration = new Configuration(); try { configuration.configure("hibernate.cfg.xml"); } catch (HibernateException e) { throw new RuntimeException(e); } final SessionFactory sessionFactory = configuration.buildSessionFactory(); final Session session1 = sessionFactory.openSession(); session1.beginTransaction(); GirlFriend21 monica = (GirlFriend21)session1.load(GirlFriend21.class,10); // Monica lewinsky record has id 10. BoyFriend21 boyfriend = monica.getBoyFriends(); System.out.println(boyfriend.getName()); // It will print Clinton Name monica.setBoyFriends(null); // It will not impact relationship session1.getTransaction().commit(); session1.close(); final Session session2 = sessionFactory.openSession(); session2.beginTransaction(); BoyFriend21 clinton = (BoyFriend21)session2.load(BoyFriend21.class,10); // Bill clinton record GirlFriend21 girlfriend = clinton.getGirlFriend(); System.out.println(girlfriend.getName()); // It will print Monica name. //But if Clinton[Who owns the relationship as per "mappedby" rule can break this] clinton.setGirlFriend(null); // Now if Monica tries to check BoyFriend Details, she will find Clinton is no more her boyFriend session2.getTransaction().commit(); session2.close(); final Session session3 = sessionFactory.openSession(); session1.beginTransaction(); monica = (GirlFriend21)session3.load(GirlFriend21.class,10); // Monica lewinsky record has id 10. boyfriend = monica.getBoyFriends(); System.out.println(boyfriend.getName()); // Does not print Clinton Name session3.getTransaction().commit(); session3.close(); } }


Para entender esto, debes dar un paso atrás. En OO, el cliente posee los pedidos (los pedidos son una lista en el objeto del cliente). No puede haber un pedido sin un cliente. Entonces el cliente parece ser el dueño de los pedidos.

Pero en el mundo SQL, un elemento contendrá un puntero al otro. Como hay 1 cliente para N pedidos, cada pedido contiene una clave externa para el cliente al que pertenece. Esta es la "conexión" y esto significa que la orden "posee" (o contiene literalmente) la conexión (información). Esto es exactamente lo opuesto al mundo OO / modelo.

Esto puede ayudar a entender:

public class Customer { // This field doesn''t exist in the database // It is simulated with a SQL query // "OO speak": Customer owns the orders private List<Order> orders; } public class Order { // This field actually exists in the DB // In a purely OO model, we could omit it // "DB speak": Order contains a foreign key to customer private Customer customer; }

El lado inverso es el OO "propietario" del objeto, en este caso el cliente. El cliente no tiene columnas en la tabla para almacenar las órdenes, por lo que debe indicarle en qué parte de la tabla de órdenes puede guardar estos datos (lo que sucede a través de mappedBy ).


Reglas simples de relaciones bidireccionales:

1. Para las relaciones bidireccionales de muchos a uno, los muchos lados siempre son el lado dueño de la relación. Ejemplo: 1 habitación tiene muchas personas (una persona pertenece solo a una habitación) -> propietario es una persona

2. Para relaciones bidireccionales uno a uno, el lado propietario corresponde al lado que contiene la clave externa correspondiente.

3. Para muchas relaciones bidireccionales, cualquiera de las partes puede ser el lado propietario.

Hope puede ayudarte.