EJB 3.0(Public Draft)入門記 Java Persistence API Chapter3 その10

前回に引き続き、エンティティリスナとコールバックメソッドがお題です。
今回は実際にエンティティリスナを使って、コールバックメソッドがいつ呼び出されるか確認してみます。


エンティティEmployeeのエンティティリスナです。

public class EmployeeEntityListener {
  @PrePersist
  public void prePersist(Employee Employee) {  
    System.out.println("@PrePersist: " + Employee.getName());
  }
  @PostPersist
  public void postPersist(Employee Employee) {
    System.out.println("@PostPersist: " + Employee.getName());
  }
  @PreRemove
  public void preRemove(Employee Employee) {  
    System.out.println("@PreRemove: " + Employee.getName());
  }
  @PostRemove
  public void postRemove(Employee Employee) {  
    System.out.println("@PostRemove: " + Employee.getName());
  }
  @PreUpdate
  public void preUpdate(Employee Employee) {  
    System.out.println("@PreUpdate: " + Employee.getName());
  }
  @PostUpdate
  public void postUpdate(Employee Employee) {
    System.out.println("@PostUpdate: " + Employee.getName());
  }
  @PostLoad
  public void postLoad(Employee Employee) {  
    System.out.println("@PostLoad: " + Employee.getName());
  }
}

エンティティEmployeeです。EntityListenerアノテーションつかってます。

@Entity(access=AccessType.FIELD)
@EntityListener(EmployeeEntityListener.class)
public class Employee {

  @Id(generate=GeneratorType.AUTO)
  private int id;

  private String name;
  
  // getter, setter省略
}

ステートレスセッションBeanです。persist、update、removeを別トランザクションでそれぞれ実行したり、同一トランザクションで一度に実行したりしてみました。mergeも試してみました。

@Stateless
public class ClientBean implements Client {

  @PersistenceContext
  private EntityManager em;
  
  public Employee persist() {
    Employee employee = new Employee();
    employee.setName("ゴン");
    em.persist(employee);
    return employee;
  }

  public void update() {
    Query query = em.createQuery("select e from Employee e where e.name = 'ゴン'");
    Employee employee = (Employee)query.getSingleResult();
      employee.setName("うさはな");
  }

  public void remove() {
    Query query = em.createQuery("select e from Employee e where e.name = 'うさはな'");
    Employee employee = (Employee)query.getSingleResult();
    em.remove(employee);
  }
  
  public void persistUpdateRemove() {
    persist();
    update();
    remove();
  }

  public void merge(Employee employee) {
    em.merge(employee);
  }
  
  public static void main(String[] args) throws Exception {
    EJB3StandaloneBootstrap.boot(null);
    EJB3StandaloneBootstrap.deployXmlResource("ejb3-deployment.xml");

    InitialContext ctx = new InitialContext();
    Client client = (Client) ctx.lookup(Client.class.getName());

    System.out.println("## PERSIST");
    client.persist();
    System.out.println("\n## UPDATE");
    client.update();
    System.out.println("\n## REMOVE");
    client.remove();
    System.out.println("\n## PERSIST AND REMOVE");
    client.persistUpdateRemove();
    System.out.println("\n## MERGE");
    Employee employee = client.persist();
    employee.setName("たくや");
    client.merge(employee);
    
    EJB3StandaloneBootstrap.shutdown();
  }
}

実行結果。

## PERSIST
@PrePersist: ゴン
Hibernate: insert into Employee (name, id) values (?, null)
Hibernate: call identity()
@PostPersist: ゴン

## UPDATE
Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ where employee0_.name='ゴン'
@PostLoad: ゴン
@PreUpdate: うさはな
Hibernate: update Employee set name=? where id=?
@PostUpdate: うさはな

## REMOVE
Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ where employee0_.name='うさはな'
@PostLoad: うさはな
@PreRemove: うさはな
Hibernate: delete from Employee where id=?
@PostRemove: うさはな

## PERSIST AND REMOVE
@PrePersist: ゴン
Hibernate: insert into Employee (name, id) values (?, null)
Hibernate: call identity()
@PostPersist: ゴン
Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ where employee0_.name='ゴン'
@PreUpdate: うさはな
Hibernate: update Employee set name=? where id=?
@PostUpdate: うさはな
Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ where employee0_.name='うさはな'
@PreRemove: うさはな
Hibernate: delete from Employee where id=?
@PostRemove: うさはな

## MERGE
@PrePersist: ゴン
Hibernate: insert into Employee (name, id) values (?, null)
Hibernate: call identity()
@PostPersist: ゴン
Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=?
@PostLoad: ゴン
@PreUpdate: たくや
Hibernate: update Employee set name=? where id=?
@PostUpdate: たくや

同一トランザクションでpersist、update、removeしたときはPostLoadコールバックメソッドが呼ばれていないです、selectのクエリは実行されていますけど。すでに永続コンテキスト内にエンティティがあってエンティティの値とデータベース内の値に変更がないからLoadする必要なしということでしょうか。
これは予想通りでしたがmergeしたときはLoadされてUpdateされるんですね。


あと、コールバックメソッドの中で別のセッションBeanを呼んでその中でEntityManagerを使うということを試してみたのですが、やっぱり怒られました。