Esta es realmente una buena pregunta que vale la pena investigar y experimentar. Hay muchas maneras de hacer el mapeo. Proponer un mejor diseño en realidad dependería de las necesidades de su aplicación. Pero así es como creo que sería una forma efectiva de implementar el mapeo:
Tendré 3 entidades separadas para Order
, Product
y Address
.
No implementaremos la relación habitual de muchos a muchos entre las 2 entidades, Order
y Product
, donde cada lado tiene una colección del otro. En su lugar, crearé otra entidad para representar la relación entre Order
y Product
, y llamémoslo ProductOrder
. Así es como se mapean sus relaciones:
Order
tiene una relación de uno a muchos conProductOrder
.ProductOrder
tiene una relación de muchos a uno conOrder
.Product
tiene una relación de uno a muchos conProductOrder
.ProductOrder
tiene una relación de muchos a uno conProduct
.
ProductOrder
La clave principal de estará compuesta por la clave principal de Order
y clave principal de Product
- así que esta será una clave compuesta. Por lo tanto, necesitaremos usar @IdClass
para mapear claves compuestas.
Ahora, aquí está el truco para lograr muchos a muchos dentro de una relación de muchos a muchos:
ProductOrder
tiene una relación de muchos a muchos con Address
.
Vea ejemplos de códigos para cada entidad mencionada anteriormente:
ENTIDAD DE PEDIDO
@Entity
@Table(name = "ORDERS")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ORDER_ID")
private Long id;
private int quantity;
@OneToMany(mappedBy = "order")
private List<ProductOrder> productOrderList = new ArrayList<ProductOrder>();
...
}
ENTIDAD DEL PRODUCTO
@Entity
@Table(name="PRODUCT")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "PRODUCT_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "product")
private List<ProductOrder> productOrderList = new ArrayList<ProductOrder>();
...
}
ENTIDAD DE DIRECCIÓN
@Entity
@Table(name="ADDRESS")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ADDRESS_ID")
private Long id;
private String state;
@ManyToMany(mappedBy = "addressList")
private List<ProductOrder> productOrderList = new ArrayList<ProductOrder>();
...
}
ENTIDAD DE PEDIDO DE PRODUCTO
@Entity
@Table(name="PRODUCT_ORDER")
@IdClass(ProductOrderId.class)
public class ProductOrder {
@Id
@ManyToOne
@JoinColumn(name="ORDER_ID")
private Order order;
@Id
@ManyToOne
@JoinColumn(name="PRODUCT_ID")
private Product product;
@ManyToMany
@JoinTable(name="PRODUCT_ORDER_ADDRESS",
joinColumns={@JoinColumn(name="ORDER_ID", referencedColumnName="ORDER_ID"),
@JoinColumn(name="PRODUCT_ID", referencedColumnName="PRODUCT_ID")},
[email protected](name="ADDRESS_ID", referencedColumnName="ADDRESS_ID"))
private List<Address> addressList = new ArrayList<Address>();
...
}
@IdClass para la entidad ProductOrder
public class ProductOrderId {
private Long order;
private Long product;
...
}
Aquí hay un código de muestra para crear las entidades y conservarlas:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Order order = new Order();
order.setQuantity(10);
em.persist(order);
Product product = new Product();
product.setName("Coffee");
em.persist(product);
Address address = new Address();
address.setState("CA");
em.persist(address);
ProductOrder productOrder = new ProductOrder();
productOrder.setOrder(order);
productOrder.setProduct(product);
productOrder.getAddressList().add(address);
address.getProductOrderList().add(productOrder);
em.persist(productOrder);
em.getTransaction().commit();
Así es como se generó el esquema en la base de datos MySQL:
Hibernate:
create table ADDRESS (
ADDRESS_ID bigint not null auto_increment,
state varchar(255),
primary key (ADDRESS_ID)
)
Hibernate:
create table ORDERS (
ORDER_ID bigint not null auto_increment,
quantity integer not null,
primary key (ORDER_ID)
)
Hibernate:
create table PRODUCT (
PRODUCT_ID bigint not null auto_increment,
name varchar(255),
primary key (PRODUCT_ID)
)
Hibernate:
create table PRODUCT_ORDER (
ORDER_ID bigint,
PRODUCT_ID bigint,
primary key (ORDER_ID, PRODUCT_ID)
)
Hibernate:
create table PRODUCT_ORDER_ADDRESS (
ORDER_ID bigint not null,
PRODUCT_ID bigint not null,
ADDRESS_ID bigint not null
)
Hibernate:
alter table PRODUCT_ORDER
add constraint FK_sl39bwx60xjbvoiujpaes74ty
foreign key (ORDER_ID)
references ORDERS (ORDER_ID)
Hibernate:
alter table PRODUCT_ORDER
add constraint FK_n0i7uxq6rxsc0mcred1cds4m9
foreign key (PRODUCT_ID)
references PRODUCT (PRODUCT_ID)
Hibernate:
alter table PRODUCT_ORDER_ADDRESS
add constraint FK_kad6crei9lgrv1nuuuff42vs8
foreign key (ADDRESS_ID)
references ADDRESS (ADDRESS_ID)
Hibernate:
alter table PRODUCT_ORDER_ADDRESS
add constraint FK_hpx0e467dvpqi5i6kxmujns2b
foreign key (ORDER_ID, PRODUCT_ID)
references PRODUCT_ORDER (ORDER_ID, PRODUCT_ID)