[英]How to implement a complex many to many relationship in JPA?
這里的數據庫架構
CREATE TABLE Products
(
id INT NOT NULL AUTO_INCREMENT,
category_id INT NOT NULL,
description VARCHAR(100),
price DECIMAL(10, 2) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (category_id) REFERENCES Categories(id)
) ENGINE = INNODB;
CREATE TABLE Orders
(
id INT NOT NULL AUTO_INCREMENT,
customer_id INT NOT NULL,
status VARCHAR(20) NOT NULL,
date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (customer_id) REFERENCES Customers(id)
) ENGINE = INNODB;
CREATE TABLE OrderDetails
(
product_id INT NOT NULL,
order_id INT NOT NULL,
quantity INT NOT NULL,
subtotal DECIMAL(10, 2) NOT NULL,
PRIMARY KEY (product_id, order_id),
FOREIGN KEY (product_id) REFERENCES Products(id),
FOREIGN KEY (order_id) REFERENCES Orders(id)
) ENGINE = INNODB;
型號
@Embeddable
public class OrderDetailPK
{
private Product product;
private Order order;
public OrderDetailPK() {}
public OrderDetailPK(Product product, Order order)
{
this.product = product;
this.order = order;
}
}
public class OrderDetail {
@EmbeddedId
private OrderDetailPK id;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="product_id", insertable=false, updatable=false)
private Product product;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="order_id", insertable=false, updatable=false)
private Order order;
private int quantity;
private double subtotal;
public OrderDetail() {}
public OrderDetail(OrderDetailPK id, int quantity, double subtotal)
{
this.product = id.getProduct();
this.order = id.getOrder();
this.quantity = quantity;
this.subtotal = subtotal;
}
// getters, setters
}
public class Product {
@Id
private int id;
private String description;
private double price;
@ManyToOne
@JoinColumn(name="category_id")
private Category category;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "Products")
private List<OrderDetail> orderDetail;
}
public class Order {
@Id
private int id;
@ManyToOne
@JoinColumn(name="customer_id")
private Customer customer;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "Orders")
private List<OrderDetail> orderDetail;
}
由於某些原因,我不斷收到錯誤消息
Concrete type "class models.OrderDetail" with application identity does not declare any primary key fields.
誰能指出我的問題所在? 謝謝
當我之前這樣做時(如本問答中所述 ),我在可嵌入ID原語中創建了字段(對應於所引用實體的ID字段),然后在實體中使用@MapsId
。 我相信這是滿足所有要求的最簡單的方法(我敢說是對的):實體中的字段是關系,ID類中的字段是原始字段,每列都被精確映射一次( @MapsId
字段)不是真正的映射,而是別名。
將其應用於您的案例,ID類如下所示:
@Embeddable
public class OrderDetailPK {
private final int productId;
private final int orderId;
public OrderDetailPK(int productId, int orderId) {
this.productId = productId;
this.orderId = orderId;
}
}
實體類如下所示:
public class OrderDetail {
@EmbeddedId
private OrderDetailPK id;
@ManyToOne(cascade = CascadeType.ALL)
@MapsId("productId")
private Product product;
@ManyToOne(cascade = CascadeType.ALL)
@MapsId("orderId")
private Order order;
private int quantity;
private double subtotal;
public OrderDetail(Product product, Order order, int quantity, double subtotal) {
this.id = new OrderDetailPK(product.getId(), order.getId());
this.product = product;
this.order = order;
this.quantity = quantity;
this.subtotal = subtotal;
}
protected OrderDetail() {}
}
首先, OrderDetailPK
必須實現Serializable
。
其次,請指定您要使用的ID,因為您已將product_id
和order_id
列指定為insertable=false, updatable=false
(只讀)。
因此,您需要嘗試以下操作:
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "product_id",column = @Column(name = "product_id")),
@AttributeOverride(name = "listingId",column= @Column(name = "order_id"))
})
private OrderDetailPK id;
您可以在這里找到更多信息:
http://docs.oracle.com/javaee/6/api/javax/persistence/EmbeddedId.html
http://docs.oracle.com/javaee/6/api/javax/persistence/AttributeOverride.html
從EmbeddedId
javadoc:
不支持在嵌入式id類中定義的關系映射。
所以你不能用這種方式。 我不認為JPA 1指定了實現此目標的標准方法(在JPA 2中有@MapsId
但我從未嘗試過),但這是我通常所做的事情,並且大多數實現(我認為至少是Hibernate,EclipseLink和OpenJPA)都支持它:
使用基本類型聲明主鍵類:
@Embeddable
public class OrderDetailPK implements Serializable
{
private int product;
private int order;
public OrderDetailPK() {}
...
}
使用@IdClass
注釋您的實體,並使用相同的名稱但所需的類型聲明字段:
@Entity
@IdClass(OrderDetailPK.class)
public class OrderDetail {
@Id
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="product_id", insertable=false, updatable=false)
private Product product;
@Id
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="order_id", insertable=false, updatable=false)
private Order order;
...
}
(我一直將@Id
保留在實體中的字段上,但我沒有重新檢查它們是否是必需的)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.