2010-12-16 79 views
5

我想創建兩個實體,其中兩個實體都有嵌入ID。其中一個實體有兩個對另一個實體的引用,其中這兩個引用都與ManyToOne相關。Java EE 6 JPA 2 ManyToOne關係創建無效的外鍵

示例代碼如下所示;

@Embeddable 
public class ItemPK { 
    @Column(nullable = false, length = 100) 
    private String itemId; 
    @Column(name = "item_client_id", nullable = false) 
    private int clientId; 
    ... 
} 

@Entity 
@Table(name = "item") 
public class Item { 
    @EmbeddedId 
    private ItemPK id; 

    @ManyToOne 
    @JoinColumn(name = "item_client_id") 
    private Client client; 

    @OneToMany(mappedBy="item", cascade = CascadeType.ALL, orphanRemoval = true) 
    private Set<RelatedItem> relatedItems; 

    @OneToMany(mappedBy="relatedItem", cascade = CascadeType.ALL, orphanRemoval = true) 
    private Set<RelatedItem> relatedItemsRHS; 
    ... 
} 

@Embeddable 
public class RelatedItemPK { 
    @Column(name = "itemId", length = 100, nullable = false) 
    private String itemId; 
    @Column(name = "item_client_id", nullable = false) 
    private int clientId; 
    @Column(name = "relatedItemId", length = 100, nullable = false) 
    private String relatedItemId; 
    @Column(name = "related_item_client_id", nullable = false) 
    private int relatedItemClientId; 
    ... 
} 

@Entity 
@Table(name = "related_item") 
public class RelatedItem { 
    @EmbeddedId 
    private RelatedItemPK id; 

    @ManyToOne(cascade = CascadeType.ALL, optional = false) 
    @JoinColumns({ 
    @JoinColumn(name="itemId", referencedColumnName="itemId", insertable=false, updatable=false), 
    @JoinColumn(name="item_client_id", referencedColumnName="item_client_id", insertable=false, updatable=false) 
    }) 
    private Item item; 
    @ManyToOne(cascade = CascadeType.ALL, optional = false) 
    @JoinColumns({ 
    @JoinColumn(name="related_item_client_id", referencedColumnName="item_client_id", insertable=false, updatable=false), 
    @JoinColumn(name="relatedItemId", referencedColumnName="itemId", insertable=false, updatable=false) 
    }) 
    private Item relatedItem; 
    ... 
} 

問題是爲RelatedItem實體創建外鍵時,我得到了一個SQLException。這是第二個失敗的ManyToOne關係。外鍵生成SQL低於,

ALTER TABLE related_item ADD CONSTRAINT FK_related_item_related_item_client_id FOREIGN KEY (related_item_client_id, relatedItemId) REFERENCES item (item_client_id, itemId) 

由於項目表由的itemId第一個索引,然後通過item_client_id,這一說法導致MySQL產生錯誤。

我想切換列的地方,這樣的SQL應該像下面

ALTER TABLE related_item ADD CONSTRAINT FK_related_item_relatedItemId FOREIGN KEY (relatedItemId, related_item_client_id) REFERENCES item (itemId,item_client_id) 

我試圖改變的「JoinColumn」 s量級,但結果並沒有改變。我也嘗試重命名這些字段,以檢查持久性提供者是否按列名稱選擇了順序,但是結果沒有改變。

那麼,有沒有辦法強制列排序?

p.s.我用下面的東西:

  • MySQL 5.1中
  • 的EclipseLink 2.0.0
  • Java EE 6的
  • JPA 2
  • GlassFish的第三版

編輯:的EclipseLink產生下面的SQL,這無法運行;

CREATE TABLE related_item (SIMILARITY DOUBLE, widget_id INTEGER NOT NULL, relatedItemId VARCHAR(100) NOT NULL, itemId VARCHAR(100) NOT NULL, related_item_client_id INTEGER NOT NULL, item_client_id INTEGER NOT NULL, PRIMARY KEY (widget_id, relatedItemId, itemId, related_item_client_id, item_client_id)); 
CREATE TABLE item (IMAGEURL VARCHAR(2048), STATUS VARCHAR(64), URL VARCHAR(2048), PRICE DOUBLE, STOCK INTEGER, DESCRIPTION TEXT(64000), NAME VARCHAR(255), ITEMID VARCHAR(100) NOT NULL, item_client_id INTEGER NOT NULL, PRIMARY KEY (ITEMID, item_client_id)); 
ALTER TABLE related_item ADD CONSTRAINT FK_related_item_itemId FOREIGN KEY (itemId, item_client_id) REFERENCES item (itemId, item_client_id); 
ALTER TABLE related_item ADD CONSTRAINT FK_related_item_related_item_client_id FOREIGN KEY (related_item_client_id, relatedItemId) REFERENCES item (item_client_id, itemId); 
ALTER TABLE item ADD CONSTRAINT FK_item_item_client_id FOREIGN KEY (item_client_id) REFERENCES client (ID); 
+0

什麼是錯誤?約束中字段的順序應該沒有影響。(還包括產生錯誤的SQL生成的數據庫) – James 2010-12-17 13:41:22

+0

約束的順序在MySQL中很重要,在目標表中必須有一個對應的索引,其中索引的第一個關鍵字等於約束列表中的第一個字段。 – bdaylik 2010-12-20 08:07:41

回答

1

請包括堆棧跟蹤。不過,我強烈建議你跳過@JoinColumn標記,除非你有自己指定外鍵的好理由。通過在其中一個方向上指定mappedBy屬性,JPA可以確定自己該做什麼。

Java EE 6和JPA花費了大量精力來實現Convention over Configuration,這意味着大多數情況下,事情都可以開箱即用。對於程序員來說,這是您所期望的,因爲您的鍋爐板代碼較少,而且這對於JPA和Jave EE容器實現者來說是非常有用的,因爲它使他們可以自由選擇性能最佳的解決方案。通過自己聲明外鍵關係,你可以搶走你和JPA的這個優勢。

編輯:事實上,我懷疑指定mappedBy和指定@JoinTable可能是您的問題的根本原因。但我需要查看堆棧跟蹤以確認。

+0

我在很多不同的地方都使用了mappedBy和@JoinColumns,但這是我唯一遇到麻煩的地方。 順便說一句:我嘗試刪除@JoinColumns,但我得到以下異常, 該字段存在多個可寫映射[related_item.item_client_id]。只有一個可以被定義爲可寫,所有其他的只能被指定爲只讀。 我不知道任何其他方式來指定一個字段只讀。 – bdaylik 2010-12-20 08:09:20

0

列的順序應該沒有關係。如果確實如此,那麼您可以更改索引中的順序以匹配,或更改列出主鍵的順序,或者僅使用腳本來生成DDL。