EJB 3.0(Public Draft)入門記 Java Persistence API Chapter3 その3
今回扱うのはエンティティのライフサイクルの削除です。
3.2.2 Removal
あるエンティティXに適用されるremove操作のセマンティクスは次のとおりです。- Xが新しく(new)生成されたエンティティならば、remove操作は無視される。しかし、エンティティXから他のエンティティへのリレーションシップにcascade=REMOVEもしくはcascade=ALLがアノテートされている場合、remove操作はXに参照されるエンティティにカスケードされる。
- Xが管理された(managed)エンティティならば、remove操作により削除される。エンティティXから他のエンティティへのリレーションシップにcascade=REMOVEもしくはcascade=ALLがアノテートされている場合、remove操作はXに参照されるエンティティにカスケードされる。
- Xが切り離された(detached)オブジェクトならばIllegalArgumentExceptionがスローされる(すなわちトランザクションのコミットが失敗する)。
- Xが削除された(removed)エンティティならば無視される。
- 削除された(removed)エンティティXはトランザクションのコミット時もしくはコミット前にDBから削除される、またはflush操作の実行の結果としてDBから削除される。削除された(removed)エンティティへのアクセスは未定義。
2番目のセマンティクス(管理されたエンティティに対するremove操作)を試してみます。エンティティのコードは前回とまったく同じ。AddressがエンティティXでEmployeeがAddressから参照されるエンティティ。AddressからEmployeeへのリレーションシップに「cascade = CascadeType.ALL」を指定してます。
@Entity(access=AccessType.FIELD) public class Employee implements Serializable { @Id(generate=GeneratorType.AUTO) private int id; private String name; @ManyToOne private Address address; // getter, setter省略 }
@Entity(access=AccessType.FIELD) public class Address implements Serializable { @Id(generate=GeneratorType.AUTO) private int id; private String name; @OneToMany(mappedBy="address", cascade = CascadeType.ALL ) private Collectionemployees = new HashSet (); public void addEmployee(Employee employee) { this.employees.add(employee); employee.setAddress(this); } // getter, setter省略 }
@Stateless public class ClientBean implements Client { @PersistenceContext private EntityManager em; public void main() { Address address = new Address(); address.setName("京都"); Employee employee1 = new Employee(); employee1.setName("ゴン"); address.addEmployee(employee1); Employee employee2 = new Employee(); employee2.setName("うさはな"); address.addEmployee(employee2); em.persist(address); print(); em.remove(address); print(); } private void print() { Query query = em.createQuery("from Employee"); for (Object each : query.getResultList()) { Employee e = (Employee) each; System.out.println(e.getName() + " : " + e.getAddress().getName()); } } 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()); client.main(); EJB3StandaloneBootstrap.shutdown(); }
実行結果
Hibernate: insert into Address (name, id) values (?, null) Hibernate: call identity() Hibernate: insert into Employee (name, address_id, id) values (?, ?, null) Hibernate: call identity() Hibernate: insert into Employee (name, address_id, id) values (?, ?, null) Hibernate: call identity() Hibernate: select employee0_.id as id1_, employee0_.name as name1_, employee0_.address_id as address3_1_ from Employee employee0_ うさはな : 京都 ゴン : 京都 Hibernate: delete from Employee where id=? Hibernate: delete from Employee where id=? Hibernate: delete from Address where id=? Hibernate: select employee0_.id as id1_, employee0_.name as name1_, employee0_.address_id as address3_1_ from Employee employee0_
OK。いったん追加されてから削除されています。
1番目のセマンティクス(新しく追加されたエンティティに対するremove操作)も試してみました。上のClientBeanからpersistするところをコメントアウトしただけです。新規のエンティティに対するremove操作は無視されるとあるんですが、実行するとorg.hibernate.StaleStateExceptionをラップしたEJBExceptionがおきます。なぜ。どこかでPersistent APIの仕様に従うかどうかを設定しなければいけない?Embeddable EJBがまだAlpha 1だから?
4番目のセマンティクス(削除されたエンティティに対するremove操作)も試してみました。これはOKでした。削除されたエンティティにremove操作をしても何もおこりません。仕様どおり無視されているようです。