JPA ManyToMany Join Table具有PK的所有属性

我正在使用Hibernate 3.3.1并且正在建模这个示例表结构 ,但是我在创建具有额外属性的连接表时遇到了麻烦。

它是OrderProduct表之间的多对多关系。 连接表是Order Detail表。 我按照这里提到的方法。

现在我有了实体

 @Entity @Table(name = "Orders") public class Order { @OneToMany(mappedBy="order") private List orderItems; } 

 @Entity @Table(name="PRODUCTS") public class Product { @OneToMany(mappedBy="product") private List orderItems; } 

 @Entity @IdClass(OrderDetail.class) @Table(name = "ORDER_DETAIL") public class OrderDetail implements Serializable { @Id @Column(name="ORDER_ID") private Long orderId; @Id @Column(name="PRODUCT_ID") private Long productId; @Column(name = "PRICE") private double price; @Column(name = "LAST_UPDATED_TIME") private Date lastUpdatedTime; @ManyToOne @JoinColumn(name = "ORDER_ID") private Order order; @ManyToOne @JoinColumn(name = "PRODUCT_ID") private Product product; } 

 public class OrderDetailId implements Serializable { private Long orderId; private Long productId; } 

我使用Apache Derby进行测试,但是我遇到了生成的表结构的问题。

 CREATE TABLE ORDER_DETAIL ( PRODUCT_ID BIGINT NOT NULL, ORDER_ID BIGINT NOT NULL, LAST_UPDATED_TIME TIMESTAMP NOT NULL, PRICE DOUBLE NOT NULL ); CREATE INDEX SQL120323142938020 ON ORDER_DETAIL (PRODUCT_ID ASC); CREATE UNIQUE INDEX SQL120323142937810 ON ORDER_DETAIL (PRODUCT_ID ASC, ORDER_ID ASC, LAST_UPDATED_TIME ASC, PRICE ASC); ALTER TABLE ORDER_DETAIL ADD CONSTRAINT SQL120323142937810 PRIMARY KEY (PRODUCT_ID, ORDER_ID, LAST_UPDATED_TIME, PRICE); ALTER TABLE ORDER_DETAIL ADD CONSTRAINT FK4A94AA82CC6D989A FOREIGN KEY (PRODUCT_ID) REFERENCES PRODUCTS (PROD_ID); 

它似乎已创建我的所有列作为主键。 为什么会这样?

您使用实体的类作为IdClass的参数。 这是不正确的。 应使用Id类。 另外,不需要在连接实体中用于id的单独字段。

去寻找下面的代码。 我不能保证它可以在如此旧的Hibernate版本中运行,但绝对可以肯定。 无论如何都值得尝试。 如果你想使用JPA 2.0function,更新到至少3.5.X版本(或者更确切地说是更新版本)也不会有什么坏处。 为了节省空间,剥离了构造者/平等等。

 @Entity @Table(name = "Orders") public class Order { @Id Long id; @OneToMany(mappedBy="order") private List orderItems; } @Entity @Table(name="PRODUCTS") public class Product { @Id Long id; @OneToMany(mappedBy="product") private List orderItems; } @Entity @IdClass(OrderDetailId.class) @Table(name = "ORDER_DETAIL") public class OrderDetail implements Serializable { @Id @ManyToOne @JoinColumn(name = "ORDER_ID") private Order order; @Id @ManyToOne @JoinColumn(name = "PRODUCT_ID") private Product product; @Column(name = "PRICE") private double price; //Maybe you also want to use @TemporalType here @Column(name = "LAST_UPDATED_TIME") private Date lastUpdatedTime; } public class OrderDetailId implements Serializable { private Long order; private Long product; } 

更新15/08/2017在JPA 2.1及更高版本中,您不需要为复合ID添加类,您可以这样做:

 @Entity @Table(name = "ORDER_DETAIL") public class OrderDetail implements Serializable { @Id @ManyToOne @JoinColumn(name = "ORDER_ID") private Order order; @Id @ManyToOne @JoinColumn(name = "PRODUCT_ID") private Product product; @Column(name = "PRICE") private double price; //Maybe you also want to use @TemporalType here @Column(name = "LAST_UPDATED_TIME") private Date lastUpdatedTime; } 

下面的代码似乎根据需要生成表,我在MySQL上测试了它(只是表创建,而不是CRUD):

 @Entity @Table(name = "orders") public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy = "orderDetailId.order") private List orderItems; //get set ….. } @Entity @Table(name="products") public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy = "orderDetailId.product") private List orderItems; //get set …… } @Entity @Table(name = "order_detail") public class OrderDetail { @Id private OrderDetailId orderDetailId; private double price; @Temporal(TemporalType.TIMESTAMP) private Date lastUpdatedTime; //get set …. } @Embeddable public class OrderDetailId implements Serializable{ private Order order; private Product product; @ManyToOne(fetch=FetchType.LAZY) @Access(AccessType.PROPERTY) public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } @ManyToOne(fetch=FetchType.LAZY) @Access(AccessType.PROPERTY) public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } //hash code equals override } 

Hibernate DEBUG详细信息如下

 DEBUG: org.hibernate.tool.hbm2ddl.SchemaUpdate - create table order_detail (lastUpdatedTime datetime, price double precision not null, product_id bigint, order_id bigint, primary key (order_id, product_id)) ENGINE=InnoDB DEBUG: org.hibernate.tool.hbm2ddl.SchemaUpdate - create table orders (id bigint not null auto_increment, primary key (id)) ENGINE=InnoDB DEBUG: org.hibernate.tool.hbm2ddl.SchemaUpdate - create table products (id bigint not null auto_increment, primary key (id)) ENGINE=InnoDB DEBUG: org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table order_detail add index FK23AE5A622128CF91 (order_id), add constraint FK23AE5A622128CF91 foreign key (order_id) references orders (id) DEBUG: org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table order_detail add index FK23AE5A62EB201631 (product_id), add constraint FK23AE5A62EB201631 foreign key (product_id) references products (id) 

使用@ManyToMany批注在逻辑上定义了多对多关联。 您还必须使用@JoinTable注释来描述关联表和连接条件。 如果关联是双向的,则一方必须是所有者,一方必须是反向结束(即,在更新关联表中的关系值时将忽略它)。 我在员工和雇主表之间举了一些例子。 因此,您可以修改代码。

 @Entity public class Employer implements Serializable { @ManyToMany( targetEntity=org.hibernate.test.metadata.manytomany.Employee.class, cascade={CascadeType.PERSIST, CascadeType.MERGE} ) @JoinTable( name="EMPLOYER_EMPLOYEE", joinColumns=@JoinColumn(name="EMPER_ID"), inverseJoinColumns=@JoinColumn(name="EMPEE_ID") ) public Collection getEmployees() { return employees; } ... } @Entity public class Employee implements Serializable { @ManyToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "employees", targetEntity = Employer.class ) public Collection getEmployers() { return employers; } }