2017-01-15 43 views
1

我嘗試實施若干年前這裏提到了同樣的問題: Hibernate many to many with a composite key with one field shared on either side of the relationshipHibernate的多對多關係與共同的外交重點

我有一個菜單和項目類和要實現的單向關係,一個菜單保存所有它包含的項目。

Menu and Item both have composite keys out of the merchant_id foreign key and an auto incremental itemId/menuId.(EER圖圖片)

因爲Hibernate無法檢索自動生成的ID,當我宣佈複合鍵和ID是系統中唯一的,我救實體無需額外embeddedId PKClass:

@Entity 
@Table(name="ITEM") 
public class Item extends AbstractTimestampEntity{ 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    @Column(name="itemId", nullable=false) 
    private long itemId; 
    @ManyToOne 
    @JoinColumn(name="merchantId", nullable=false) 
    private Merchant merchant; 
    @Column(name="name", length=45) 
    private String name; 
    @Column(name="description" , length=200) 
    private String description; 
    @Column(name="price") 
    private double price; 

    public Item(){} // getters & setters 

@Entity 
@Table(name="MENU") 
public class Menu { 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    @Column(name="menuId", nullable=false) 
    private long menuId; 
    @ManyToOne 
    @JoinColumn(name="merchantId", nullable=false) 
    private Merchant merchant; 
    @Column(name="name", length=45) 
    private String name; 
    @ManyToMany 
    @JoinTable(name="MENU_ITEM", joinColumns = { 
     @JoinColumn(name="menuId", nullable=false, updatable=false)}, 
     //@JoinColumn(name="merchant.merchantId", nullable=false, updatable=false)}, 
     inverseJoinColumns = { @JoinColumn(name="itemId", nullable=false, updatable=false)}) 
     //      @JoinColumn(name="merchantId", nullable=false, updatable=false)}) 
    private List<Item> items = new ArrayList<Item>(); // constructor, getters & setters 

你可以從註釋的代碼看,這裏是點是我的問題的用武之地,如何將實體映射現在最好w ^沒有修改我的規範化數據庫表? (他們需要具有相同的商戶數據庫進行驗證)

+0

可以顯示' MENU_ITEM'外鍵? –

回答

0

我懷疑你可能想是這樣的:

CREATE TABLE `MENU_ITEM` (
    `merchant_id` INT NOT NULL, 
    `menu_id` INT NOT NULL, 
    `item_id` INT NOT NULL, 

    PRIMARY KEY (`merchant_id`, `menu_id`, `item_id`), 

    INDEX `ix_menuitem_item` (`item_id`, `merchant_id`), 
    INDEX `ix_menuitem_menu` (`menu_id`, `merchant_id`), 
    INDEX `ix_menuitem_merchant` (`merchant_id`), 

    CONSTRAINT `fk_menuitem_merchant` 
     FOREIGN KEY (`merchant_id`) 
     REFERENCES `merchant` (`id`), 

    CONSTRAINT `fk_menuitem_menu` 
     FOREIGN KEY (`menu_id`, `merchant_id`) 
     REFERENCES `menu` (`id`, `merchant_id`), 

    CONSTRAINT `fk_menuitem_item` 
     FOREIGN KEY (`item_id`, `merchant_id`) 
     REFERENCES `item` (`id`, `merchant_id`) 
) 

但不幸的是,這是不可能的

一列可以可以使用至多1外鍵,在這種情況下MENU_ITEM.merchant_id用於3倍(至多2,除去fk_menuitem_merchant)。

所以,你可能要相當於一句:

CREATE TABLE `MENU_ITEM` (
    `merchant_id` INT NOT NULL, 
    `menu_id` INT NOT NULL, 
    `menu_merchant_id` INT NOT NULL, 
    `item_id` INT NOT NULL, 
    `item_merchant_id` INT NOT NULL, 

    PRIMARY KEY (`merchant_id`, `menu_id`, `item_id`), 

    INDEX `ix_menuitem_item` (`item_id`, `merchant_id`), 
    INDEX `ix_menuitem_menu` (`menu_id`, `merchant_id`), 
    INDEX `ix_menuitem_merchant` (`merchant_id`), 

    CONSTRAINT `fk_menuitem_merchant` 
     FOREIGN KEY (`merchant_id`) 
     REFERENCES `merchant` (`id`), 

    CONSTRAINT `fk_menuitem_menu` 
     FOREIGN KEY (`menu_id`, `menu_merchant_id`) 
     REFERENCES `menu` (`id`, `merchant_id`), 

    CONSTRAINT `fk_menuitem_item` 
     FOREIGN KEY (`item_id`, `item_merchant_id`) 
     REFERENCES `item` (`id`, `merchant_id`), 

    CHECK (`merchant_id` = `menu_merchant_id`), 
    CHECK (`merchant_id` = `item_merchant_id`) 
) 

,但不幸再次中,MySQL 不支持CHECK

正如你所看到的,這不是一個ORM問題。

所以,你有兩個選擇:

  1. 實施一些觸發模擬CHECKsee here
  2. 讓應用程序做檢查:

    @Entity 
    public class Menu 
    { 
        protected class ItemList extends AbstractList<Item> 
        { 
         protected ArrayList<Item> list; 
    
         public ItemList() 
         { 
          super(); 
          list = new ArrayList<>(); 
         } 
    
         public ItemList(Collection<? extends Item> c) 
         { 
          super(); 
          list = new ArrayList<>(c.size()); 
          addAll(c); 
         } 
    
         @Override 
         public boolean add(Item item) 
         { 
          if(!Objects.equals(merchant, item.merchant)) 
          { 
           throw new IllegalArgumentException(); 
           // or return false; 
          } 
    
          return list.add(item); 
         } 
    
         @Override 
         public Item get(int index) 
         { 
          return list.get(index); 
         } 
    
         @Override 
         public int size() 
         { 
          return list.size(); 
         } 
        } 
    
        @Id 
        @GeneratedValue(strategy = GenerationType.IDENTITY) 
        @Column(name = "id", nullable = false) 
        protected long id; 
    
        @ManyToOne 
        @JoinColumn(name = "merchant_id", nullable = false) 
        protected Merchant merchant; 
    
        @Column(name = "name", length = 45) 
        protected String name; 
    
        @ManyToMany 
        @JoinTable(name = "MENU_ITEM", 
         joinColumns = @JoinColumn(name = "menu_id"), 
         inverseJoinColumns = @JoinColumn(name = "item_id")) 
        protected List<Item> items = new ItemList(); 
    
        public List<Item> getItems() 
        { 
         return items; 
        } 
    
        public void setItems(List<Item> items) 
        { 
         this.items = new ItemList(items); 
        } 
    } 
    
+0

謝謝!是的,我正在考慮只在應用程序層進行檢查。但是我不確定是否有更好的方法不會改變標準化的DB設計。 – kaikun

+0

不客氣。我想有一個數據庫的方式:( –

相關問題