開発者ドキュメント

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)

リファレンス

マッピングドキュメンテーション]

モバイルバージョンを終了