JPA サンプル

Java Persistence APIでエンティティを作って、EntityManagerで操作(テスト)するまでのメモ。良く使いそうなアノテーションを含めたサンプルです。

今回はエンティティを作るまで。次回はテストケースを書いて実行します。

Product(商品)とProductStock(商品在庫)は、お互いが誘導可能なコンポジション(商品が消えれば商品在庫も消える)。ProductStockのスーパークラスStock(在庫)を用意しておきました。

エンティティクラスは、EntityManagerのコンテキストに入れない限り、ただのPOJOですから、普通のDTOとして利用できます。しかし反対に、DTOとして設計したPOJOを、簡単にエンティティに変換できるとは限りません。

エンティティのルールに基づいて、DTOを作る。という手順が、上手な方法ではないでしょうか。POJOをキレイに設計すれば、煩雑なアクセサは激減するハズ!です(←狙いはココ)。

以下、エンティティのソースコードとコメントの羅列です。

Product.java

@Entity
public class Product implements Serializable {

  private int id;
  private String name;
  private ProductStock productStock;

  //アクセサにアノテーションを書く方法(property-based)が一般的だが、
  //フィールドにアノテーションを書く方法(field-based)もある。

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  //↑この場合、システム全体でユニークな値になる。
  // (と思う。hibernateの場合は、hibernate_sequence という
  //  デフォルトシーケンスから取得する。)

  public int getId() {
    return this.id;
  }
  public void setId(int id) {
    this.id = id;
  }

  @Column(length=64)
  //↑カラム属性を定義するときに使う。無ければ全部デフォルト。
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }

  @OneToOne(
    cascade=CascadeType.ALL, //カスケード
    fetch=FetchType.EAGER //1対多ならLAZYの方が良いかも
  )

  public ProductStock getProductStock() {
    return productStock;
  }
  public void setProductStock(ProductStock productStock) {
    this.productStock = productStock;
  }

  //以下、NetBeansが生成するコードに習って。
  @Override
  public int hashCode() {
    return (int)getId();
  }
  @Override
  public boolean equals(Object object) {
    if (!(object instanceof Product)) {
      return false;
    }
    Product other = (Product)object;
    if (this.getId() != other.getId()) return false;
    return true;
  }
}

ProductStock.java

  @Entity
  @SequenceGenerator(name="PRODUCT_STOCK_SEQ_GEN",
    sequenceName="PRODUCT_STOCK_SEQ",
    initialValue=1,allocationSize=1)

  //↑利用するシーケンスを定義。
  public class ProductStock extends Stock implements Serializable {

  //ここでは、field-basedで書いてみた。この書き方にすると、
  // persistence provider は、アクセサを経由しない。
  @Id
  @GeneratedValue(
    strategy=GenerationType.SEQUENCE,
    generator="PRODUCT_STOCK_SEQ_GEN")

  //↑任意のシーケンスからIdを取得する。
  private int id;

  @OneToOne(mappedBy="productStock")
  //↑ Product.productStockにマップ
  //エンティティ名と違う名前にマップする場合に必要。

  private Product product;

  @Temporal(TemporalType.TIMESTAMP)
  //↑java.util型を java.sql型に変換する方法
  private Date updatedAt;

  //以下、単なるアクセサ
  public int getId() {
    return this.id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public Product getProduct() {
    return product;
  }
  public void setProduct(Product product) {
    this.product = product;
  }
  public Date getUpdatedAt() {
    return updatedAt;
  }
  public void setUpdatedAt(Date updatedAt) {
    this.updatedAt = updatedAt;
  }

  @Override
  public int hashCode() {
    :
  }
  @Override
  public boolean equals(Object object) {
    :
  }
}

Stock.java

@MappedSuperclass
//↑@Entityのスーパークラスであることを宣言
// このクラスを継承したエンティティは、
// このクラスのプロパティもテーブルカラムにマップする。

public class Stock {

  private int amount;
  private String status;

  public int getAmount() {
    return amount;
  }
  public void setAmount(int amount) {
    this.amount = amount;
  }

  @Transient
  //↑テーブルには入れたくないときに宣言する。
  public String getStatus() {
    if( this.amount <= 0 )
      this.status = "在庫切れ";
    else if( this.amount <= 10 )
      this.status = "残少";
    else
      this.status = "在庫アリ";
    return this.status;
  }

  public void setStatus(String status){
    this.status = status;
  }
}

コメント

コメントしてください

closed.