如何在JPA中实现复杂的多对多关系?

这里是db模式

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; } public class Order { @Id private int id; @ManyToOne @JoinColumn(name="customer_id") private Customer customer; @OneToMany(cascade = CascadeType.ALL, mappedBy = "Orders") private List orderDetail; } 

由于某些原因,我不断收到错误

 Concrete type "class models.OrderDetail" with application identity does not declare any primary key fields. 

谁能指出我问题出在哪里? 谢谢

当我之前这样做时(详见本问答 ),我在可嵌入的ID原语中创建了字段(对应于所引用实体的ID字段),然后在实体中使用@MapsId 。 我相信这是满足所有要求的最简单(并且我敢说是正确的):实体中的字段是关系,ID类中的字段是原始的,每列@MapsId映射一次( @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_idorder_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保留在实体的字段中,但如果它们是强制性的,我没有重新检查)