Hibernate – 多対多の例 – join table + extra column(Annotation)
このチュートリアルでは、Hibernateを使用して「多対多のテーブル関係、
結合テーブルの
余分の列」を実装する方法を説明します。
1.多対多テーブルの結合テーブルの余分な列
STOCKとCATEGORYの多対多の関係は、STOCK
CATEGORYという名前の第3の/結合テーブルと、余分な “created
by`”列と “created__date`”列でリンクされています。
MySQLテーブルスクリプト
CREATE TABLE `stock` ( `STOCK__ID` INT(10) UNSIGNED NOT NULL AUTO__INCREMENT, `STOCK__CODE` VARCHAR(10) NOT NULL, `STOCK__NAME` VARCHAR(20) NOT NULL, PRIMARY KEY (`STOCK__ID`) USING BTREE, UNIQUE KEY `UNI__STOCK__NAME` (`STOCK__NAME`), UNIQUE KEY `UNI__STOCK__ID` (`STOCK__CODE`) USING BTREE ) CREATE TABLE `category` ( `CATEGORY__ID` INT(10) UNSIGNED NOT NULL AUTO__INCREMENT, `NAME` VARCHAR(10) NOT NULL, `DESC` VARCHAR(255) NOT NULL, PRIMARY KEY (`CATEGORY__ID`) USING BTREE ) CREATE TABLE `stock__category` ( `STOCK__ID` INT(10) UNSIGNED NOT NULL, `CATEGORY__ID` INT(10) UNSIGNED NOT NULL, `CREATED__DATE` DATE NOT NULL, `CREATED__BY` VARCHAR(10) NOT NULL, PRIMARY KEY (`STOCK__ID`,`CATEGORY__ID`), CONSTRAINT `FK__CATEGORY__ID` FOREIGN KEY (`CATEGORY__ID`) REFERENCES `category` (`CATEGORY__ID`), CONSTRAINT `FK__STOCK__ID` FOREIGN KEY (`STOCK__ID`) REFERENCES `stock` (`STOCK__ID`) )
2.プロジェクトの構成
このチュートリアルのファイルプロジェクトの構造を見直してください。
3. Hibernate/JPAアノテーション
Hibernate/JBossツールで生成された注釈コードは、この第3テーブルの追加の列シナリオでは機能しません。それを動作させるには、
` @ AssociationOverride
“を使用するようにコードをカスタマイズし、` `StockCategory.java`で多対多関係を表現する必要があります。
下記のカスタマイズされたコードをご覧ください:
File:Stock.java
package com.mkyong.stock; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import static javax.persistence.GenerationType.IDENTITY; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @Entity @Table(name = "stock", catalog = "mkyongdb", uniqueConstraints = { @UniqueConstraint(columnNames = "STOCK__NAME"), @UniqueConstraint(columnNames = "STOCK__CODE") }) public class Stock implements java.io.Serializable { private Integer stockId; private String stockCode; private String stockName; private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0); public Stock() { } public Stock(String stockCode, String stockName) { this.stockCode = stockCode; this.stockName = stockName; } public Stock(String stockCode, String stockName, Set<StockCategory> stockCategories) { this.stockCode = stockCode; this.stockName = stockName; this.stockCategories = stockCategories; } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "STOCK__ID", unique = true, nullable = false) public Integer getStockId() { return this.stockId; } public void setStockId(Integer stockId) { this.stockId = stockId; } @Column(name = "STOCK__CODE", unique = true, nullable = false, length = 10) public String getStockCode() { return this.stockCode; } public void setStockCode(String stockCode) { this.stockCode = stockCode; } @Column(name = "STOCK__NAME", unique = true, nullable = false, length = 20) public String getStockName() { return this.stockName; } public void setStockName(String stockName) { this.stockName = stockName; } @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.stock", cascade=CascadeType.ALL) public Set<StockCategory> getStockCategories() { return this.stockCategories; } public void setStockCategories(Set<StockCategory> stockCategories) { this.stockCategories = stockCategories; } }
__File:Stock Category.java
package com.mkyong.stock; import java.util.Date; import javax.persistence.AssociationOverride; import javax.persistence.AssociationOverrides; import javax.persistence.Column; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; @Entity @Table(name = "stock__category", catalog = "mkyongdb") @AssociationOverrides({ @AssociationOverride(name = "pk.stock", joinColumns = @JoinColumn(name = "STOCK__ID")), @AssociationOverride(name = "pk.category", joinColumns = @JoinColumn(name = "CATEGORY__ID")) }) public class StockCategory implements java.io.Serializable { private StockCategoryId pk = new StockCategoryId(); private Date createdDate; private String createdBy; public StockCategory() { } @EmbeddedId public StockCategoryId getPk() { return pk; } public void setPk(StockCategoryId pk) { this.pk = pk; } @Transient public Stock getStock() { return getPk().getStock(); } public void setStock(Stock stock) { getPk().setStock(stock); } @Transient public Category getCategory() { return getPk().getCategory(); } public void setCategory(Category category) { getPk().setCategory(category); } @Temporal(TemporalType.DATE) @Column(name = "CREATED__DATE", nullable = false, length = 10) public Date getCreatedDate() { return this.createdDate; } public void setCreatedDate(Date createdDate) { this.createdDate = createdDate; } @Column(name = "CREATED__BY", nullable = false, length = 10) public String getCreatedBy() { return this.createdBy; } public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; StockCategory that = (StockCategory) o; if (getPk() != null ? !getPk().equals(that.getPk()) : that.getPk() != null) return false; return true; } public int hashCode() { return (getPk() != null ? getPk().hashCode() : 0); } }
File:StockCategoryId.java
package com.mkyong.stock; import javax.persistence.Embeddable; import javax.persistence.ManyToOne; @Embeddable public class StockCategoryId implements java.io.Serializable { private Stock stock; private Category category; @ManyToOne public Stock getStock() { return stock; } public void setStock(Stock stock) { this.stock = stock; } @ManyToOne public Category getCategory() { return category; } public void setCategory(Category category) { this.category = category; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; StockCategoryId that = (StockCategoryId) o; if (stock != null ? !stock.equals(that.stock) : that.stock != null) return false; if (category != null ? !category.equals(that.category) : that.category != null) return false; return true; } public int hashCode() { int result; result = (stock != null ? stock.hashCode() : 0); result = 31 ** result + (category != null ? category.hashCode() : 0); return result; } }
File:Category.java
package com.mkyong.stock; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import static javax.persistence.GenerationType.IDENTITY; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "category", catalog = "mkyongdb") public class Category implements java.io.Serializable { private Integer categoryId; private String name; private String desc; private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0); public Category() { } public Category(String name, String desc) { this.name = name; this.desc = desc; } public Category(String name, String desc, Set<StockCategory> stockCategories) { this.name = name; this.desc = desc; this.stockCategories = stockCategories; } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "CATEGORY__ID", unique = true, nullable = false) public Integer getCategoryId() { return this.categoryId; } public void setCategoryId(Integer categoryId) { this.categoryId = categoryId; } @Column(name = "NAME", nullable = false, length = 10) public String getName() { return this.name; } public void setName(String name) { this.name = name; } @Column(name = "[DESC]", nullable = false) public String getDesc() { return this.desc; } public void setDesc(String desc) { this.desc = desc; } @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.category") public Set<StockCategory> getStockCategories() { return this.stockCategories; } public void setStockCategories(Set<StockCategory> stockCategories) { this.stockCategories = stockCategories; } }
完了したら、多対多の関係が今働いているはずです。
4.実行 – ケース1
新しいカテゴリーと新しい在庫のため。
session.beginTransaction(); Stock stock = new Stock(); stock.setStockCode("7052"); stock.setStockName("PADINI"); Category category1 = new Category("CONSUMER", "CONSUMER COMPANY"); //new category, need save to get the id first session.save(category1); StockCategory stockCategory = new StockCategory(); stockCategory.setStock(stock); stockCategory.setCategory(category1); stockCategory.setCreatedDate(new Date());//extra column stockCategory.setCreatedBy("system");//extra column stock.getStockCategories().add(stockCategory); session.save(stock); session.getTransaction().commit();
出力…
Hibernate: insert into mkyongdb.category (`DESC`, NAME) values (?, ?) Hibernate: insert into mkyongdb.stock (STOCK__CODE, STOCK__NAME) values (?, ?) Hibernate: select stockcateg__.CATEGORY__ID, stockcateg__.STOCK__ID, stockcateg__.CREATED__BY as CREATED1__2__, stockcateg__.CREATED__DATE as CREATED2__2__ from mkyongdb.stock__category stockcateg__ where stockcateg__.CATEGORY__ID=? and stockcateg__.STOCK__ID=? Hibernate: insert into mkyongdb.stock__category (CREATED__BY, CREATED__DATE, CATEGORY__ID, STOCK__ID) values (?, ?, ?, ?)
5.それを実行する – ケース2
既存のカテゴリと新しい在庫を取得します。
session.beginTransaction(); Stock stock = new Stock(); stock.setStockCode("7052"); stock.setStockName("PADINI"); //assume category id is 7 Category category1 = (Category)session.get(Category.class, 7); StockCategory stockCategory = new StockCategory(); stockCategory.setStock(stock); stockCategory.setCategory(category1); stockCategory.setCreatedDate(new Date());//extra column stockCategory.setCreatedBy("system");//extra column stock.getStockCategories().add(stockCategory); session.save(stock); session.getTransaction().commit();
出力…
Hibernate: select category0__.CATEGORY__ID as CATEGORY1__1__0__, category0__.`DESC` as DESC2__1__0__, category0__.NAME as NAME1__0__ from mkyongdb.category category0__ where category0__.CATEGORY__ID=? Hibernate: insert into mkyongdb.stock (STOCK__CODE, STOCK__NAME) values (?, ?) Hibernate: select stockcateg__.CATEGORY__ID, stockcateg__.STOCK__ID, stockcateg__.CREATED__BY as CREATED1__2__, stockcateg__.CREATED__DATE as CREATED2__2__ from mkyongdb.stock__category stockcateg__ where stockcateg__.CATEGORY__ID=? and stockcateg__.STOCK__ID=? Hibernate: insert into mkyongdb.stock__category (CREATED__BY, CREATED__DATE, CATEGORY__ID, STOCK__ID) values (?, ?, ?, ?)
完了しました。
ダウンロードする – リンク://wp-content/uploads/2011/04/Hibernate-many-to-many-third-table-annotation.zip[Hibernate-many-to-many-third-table-annotation.zip]( 13KB)
リファレンス
マッピングドキュメンテーション]