2012-03-23 94 views
3

我正在使用Hibernate 3.3.1,並且正沿着建模this sample table structure的方向發展,但我在創建具有額外屬性的連接表時遇到問題。JPA ManyToMany Join Table具有所有屬性PK

這是OrderProduct表之間的多對多關係。連接表是Order Detail表。我遵循了here提到的方法。

現在我有實體

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

@Entity 
@Table(name="PRODUCTS") 
public class Product { 
    @OneToMany(mappedBy="product") 
    private List<OrderDetail> 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); 

看來它已經創建了我所有的列作爲主鍵。這是爲什麼?

回答

7

您使用您的實體的類作爲IdClass的參數。這是不正確的。應使用Id類。此外,不需要爲連接實體中的id分隔字段。

去找類似下面的代碼。我不能保證它能在這樣一箇舊版本的Hibernate中工作,但對於永遠不會有效的工作。值得嘗試。如果你想使用JPA 2.0特性,至少要升級到3.5.X版本(或者更新的版本)並沒有什麼壞處。構造函數/等等被剝離以節省空間。

@Entity 
@Table(name = "Orders") 
public class Order { 
    @Id Long id; 
    @OneToMany(mappedBy="order") 
    private List<OrderDetail> orderItems; 
} 

@Entity 
@Table(name="PRODUCTS") 
public class Product { 
    @Id Long id; 
    @OneToMany(mappedBy="product") 
    private List<OrderDetail> 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; 
} 

UPDATE 15/08/2017 在JPA 2.1及以上,你不需要添加一個類爲複合標識,你可以做這樣的:

@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; 
} 
+0

嗨Mikko,Ahh只是一個想法,因爲我仍然是JPA的初學者。我開始認爲@ManyToMany註釋似乎更像是一個細微差別,當你可以手動完成時?你不覺得嗎?我的理解有點淺,但那是我的印象。 – 2012-03-23 08:21:14

+0

在所有情況下,我都可以認爲正確的知道,可以在沒有ManyToMany的情況下進行映射。當關系的性質要求時,我總是傾向於使用多對多的方式,因爲它更乾淨並且代碼更少。 – 2012-03-25 14:08:07

0

多對多關聯是使用@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", 
     [email protected](name="EMPER_ID"), 
     [email protected](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; 
    } 
} 
+0

啊,是的,我認爲我的情況有點不同,因爲我有我的加入或中間表一個額外的列。遵循你的方法意味着我的'連接'表只會有兩列。 – 2012-03-23 06:58:44

+0

是的。你不需要創建第三個實體OrderDetailId。休眠會管理。 – kandarp 2012-03-23 07:09:36

+0

如何創建額外屬性'LAST_UPDATED_TIME'和'價格',然後如果我不創建第三個實體?你的方法只會創建由'EMPER_ID'和'EMPEE_ID'組成的'join'表,但如果你想在'EMPLOYER_EMPLOYEE'表上添加'狀態'列呢? – 2012-03-23 07:15:33

5

下面的代碼似乎產生表作爲需要,我已經測試它在MySQL(剛創建表,不CRUD):

@Entity 
@Table(name = "orders") 
public class Order { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 

    @OneToMany(mappedBy = "orderDetailId.order") 
    private List<OrderDetail> orderItems; 

    //get set ….. 

} 

@Entity 
@Table(name="products") 
public class Product { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 

    @OneToMany(mappedBy = "orderDetailId.product") 
    private List<OrderDetail> 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)