EJB 3.0(Public Draft)入門記 Java Persistence API Chapter2 その4

Java Persistence APIを使ってみよう。そろそろうごかしてみないと間違って覚えそうな気がするのでコード動かしてみます。

複合プライマリキーを使ったデータアクセスを行ってみます。環境はSimplified APIの入門記のときと同じでJBOSS4.0.2R1を使います。


まず、テーブル定義。僕が生まれて初めてみたデータベースの定義は超簡略化するとこんなカンジでした。本店(H.Q.)コードと支店(Branch)コードで顧客が決まるのだとおそわりました。複合プライマリキーをもちます。

CREATE TABLE Customer (
 HQCODE INTEGER,
 BRANCHCODE INTEGER,
 NAME VARCHAR(10),
 PRIMARY KEY(HQCODE, BRANCHCODE)
)


複合プライマリキーをあらわす埋め込み可能クラスです。埋め込み可能クラスはequalsとhashCodeがDBの値の等価性と同じになるように実装する必要があると書いてあったのでequalsとhashCodeを実装しました。hashCodeメソッドのコードはEffective Javaを参照したのでまちがっていはいないはず?

@Embeddable
public class CustomerPK implements Serializable {
  private int hqCode;

  private int branchCode;

  public int getBranchCode() {
    return branchCode;
  }

  public void setBranchCode(int branchCode) {
    this.branchCode = branchCode;
  }

  public int getHqCode() {
    return hqCode;
  }

  public void setHqCode(int hqCode) {
    this.hqCode = hqCode;
  }

  public int hashCode() {
    int result = 17;
    result = 37 * result + hqCode;
    result = 37 * result + branchCode;
    return result;
  }

  public boolean equals(Object other) {
    if (!(other instanceof CustomerPK)) {
      return false;
    }
    CustomerPK castOther = (CustomerPK) other;
    return this.hqCode == castOther.hqCode
        && this.branchCode == castOther.branchCode;
  }

  public String toString() {
    return hqCode + ", " + branchCode;
  }
}


Customerテーブルに対応するエンティティ。FIELDアクセスにしてみました。最初Embeddedアノテーションを使ってみたのですが怒られました。EmbeddedIDアノテーションでなければいけなかったようです。

@Entity(access=AccessType.FIELD) 
public class Customer implements Serializable {
  
  @EmbeddedId
  private CustomerPK customerPK;
  
  private String name;
  
  public CustomerPK getCustomerPK() {
    return customerPK;
  }
  
  public void setCustomerPK(CustomerPK customerPK) {
    this.customerPK = customerPK;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
  
  public String toString() {
    return customerPK + ", " + name;
  }
}


SessionBeanのビジネスインタフェースです。DAOインタフェースです。

public interface CustomerDao {
  public void persist(Customer customer);
  public void merge(Customer customer);
  public Customer getCustomerById(CustomerPK pk);
}


SessionBeanのBeanクラス。EntityManagerを使っています。

@Stateless
@Remote(CustomerDao.class)
public class CustomerDaoBean implements CustomerDao {
  
  @PersistenceContext
  private EntityManager em;

  public void persist(Customer customer) {
    em.persist(customer);
  }
  
  public void merge(Customer customer) {
    em.merge(customer);
  }
  
  public Customer getCustomerById(CustomerPK pk) {
    return em.find(Customer.class, pk);
  }
}


クライアントです。SessionBeanにアクセスします。上記のクラスたちをデプロイして実行します。

public class Client {
  public static void main(String[] args) throws Exception {
    InitialContext ctx = new InitialContext();
    
    // SessionBeanの取得
    CustomerDao dao = (CustomerDao) ctx.lookup(CustomerDao.class.getName());
    
    // エンティティ生成
    Customer customer = new Customer();
    
    // 複合プライマリキー生成
    CustomerPK pk = new CustomerPK();
    pk.setHqCode(10001);
    pk.setBranchCode(100);
    
    // 永続化と取得
    customer.setCustomerPK(pk);
    customer.setName("HOGE");
    dao.persist(customer);
    customer = dao.getCustomerById(pk);
    System.out.println(customer);
    
    // 変更と取得
    customer.setName("FOO");
    dao.merge(customer);
    customer = dao.getCustomerById(pk);
    System.out.println(customer);
  }
}


実行結果

10001, 100, HOGE
10001, 100, FOO


データの追加、取得、更新ができました。
先日までなぞだったEmbeddableアノテーションの使い方がわかったのでOK。なんだかんだで複合プライマリキーに対応しなければいけない場合があるような気がするので覚えておきたい。

今日はここまで。