2010年4月3日星期六

ADF_058:如何定制EO的增加、修改、删除操作?

开发环境:JDeveloper 11.1.2.2.0 + Oracle XE Database 10gR2。

本实验基于《使用ADF实现基于Form的CRUD (3)

ADF-BC中的EO对象写入数据库的操作本来不需要我们关心,不用写任何代码,这是使用ADF-BC的好处之一。
但在实际开发中,有时需要在EO入库前做一些其它操作,比如设置默认属性值、设置Sequence值;有时需要在插入某个EO后做一些其它事情,比如再插入另一个EO对象。
这时,就需要定制EO的增加、修改、删除操作,以及定制提交入库前后的代码。

ADF-BC为定制化提供了优美的解决方案:
1. 定制EO的增加、修改、删除操作
(1)选中需要定制的EO,为其生成对应的Entity Object Java Class,勾上“Create”、“Remove”、“Data Manipulation Methods"。

(2)定制create、remove、doDML方法

protected void create(AttributeList attributeList) {
System.out.println("################### before create:");
super.create(attributeList);
System.out.println("################### after create:");
}

public void remove() {
System.out.println("################### before remove:");
super.remove();
System.out.println("################### after remove:");
}

protected void doDML(int operation, TransactionEvent e) {
if (operation == DML_INSERT) {
System.out.println("################### doDML before insert:");
super.doDML(operation, e);
System.out.println("################### doDML after insert:");
} else if (operation == DML_UPDATE) {
System.out.println("################### doDML before update:");
super.doDML(operation, e);
System.out.println("################### doDML after update:");
} else if (operation == DML_DELETE) {
System.out.println("################### doDML before delete:");
super.doDML(operation, e);
System.out.println("################### doDML after delete:");
}
}

doDML方法说明:
(1)根据不同的操作(增加、修改、删除),选择不同的逻辑分支。
super.doDML(operation, e); 就是EO自身的入库操作代码,除非你要彻底修改它的逻辑,否则不要修改。
(2)入库前的代码,写在super.doDML(operation, e);之前。
(3)入库后的代码,写在super.doDML(operation, e);之后。
(4)关于EO常用操作代码请参考《ADF-BC中EO常用操作代码之一:查询》系列文章。


2. 定制EO提交入库前后的代码
EO提交入库分为前后两个阶段:Post Phase和Commit Phase。
(1)Post Phase
验证标记为”invalid“的EO,所有新建的和修改的EO都被标记为”invalid“的EO。
验证定义在EO上的所有验证规则,包括定制的验证规则。
由于验证规则可能会修改EO数据,因此验证过程将反复执行多次,最多执行10次,直到EO被标记为”valid"。
最后,把标记为”valid"的EO提交到数据库。
(2)Commit Phase
提交事务,将EO改变的数据写入数据库。


public void postChanges(TransactionEvent transactionEvent) {
System.out.println("################### before postChanges:");
super.postChanges(transactionEvent);
System.out.println("################### after postChanges:");
}

public void beforeCommit(TransactionEvent transactionEvent) {
System.out.println("################### before commit:");
super.beforeCommit(transactionEvent);
}

public void beforeRollback(TransactionEvent transactionEvent) {
System.out.println("################### before rollback:");
super.beforeRollback(transactionEvent);
}

public void afterCommit(TransactionEvent transactionEvent) {
super.afterCommit(transactionEvent);
System.out.println("################### after commit:");
}

public void afterRollback(TransactionEvent transactionEvent) {
super.afterRollback(transactionEvent);
System.out.println("################### after rollback:");
}


3. 运行AM
(1)点击Insert

Console输出如下:
################### before create:
################### after create:
[67] **** refreshControl() for BindingContainer :AppModule_JobsView1_0PageDef
(2)成功Insert后,点击Commit

Console输出如下:
[68] INFO: No app _def_ in BindingContext for: adfFacesContext
[69] INFO: mDCRefMap lookup failed. Does the cpx have a dataControlUsages 'dc' entry? adfFacesContext
[70] INFO: No app _def_ in BindingContext for: adfFacesContext
[71] INFO: mDCRefMap lookup failed. Does the cpx have a dataControlUsages 'dc' entry? adfFacesContext
[72] OracleSQLBuilder: SAVEPOINT 'BO_SP'
################### before postChanges:
################### doDML before insert:
[73] OracleSQLBuilder Executing, Lock 2 DML on: JOBS (Insert)
[74] INSERT buf Jobs>#i SQLStmtBufLen: 300, actual=77
[75] INSERT INTO JOBS(JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY) VALUES (:1,:2,:3,:4)
[76] Insert binding param 1: 3344
[77] Insert binding param 2: 4444
[78] Insert binding param 3: 1
[79] Insert binding param 4: 2
################### doDML after insert:
################### after postChanges:
################### before commit:
################### after commit:
[80] JobsView1 notify COMMIT ...
(3)修改EO数据,并点击Commit
Console输出如下:
[81] OracleSQLBuilder: SAVEPOINT 'BO_SP'
################### before postChanges:
[82] OracleSQLBuilder Executing doEntitySelect on: JOBS (true)
[83] Built select: 'SELECT JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY FROM JOBS Jobs'
[84] Executing LOCK...SELECT JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY FROM JOBS Jobs WHERE JOB_ID=:1 FOR UPDATE NOWAIT
[85] Where binding param 1: 3344
################### doDML before update:
[86] OracleSQLBuilder Executing, Lock 2 DML on: JOBS (Update)
[87] UPDATE buf Jobs>#u SQLStmtBufLen: 255, actual=64
[88] UPDATE JOBS Jobs SET MIN_SALARY=:1,MAX_SALARY=:2 WHERE JOB_ID=:3
[89] Update binding param 1: 3
[90] Update binding param 2: 4
[91] Where binding param 3: 3344
################### doDML after update:
################### after postChanges:
################### before commit:
################### after commit:
[92] JobsView1 notify COMMIT ...
[93] EntityCache close prepared statement
(4)点击Delete

Console输出如下:
################### before remove:
[94] QueryCollection: afterRemove(0)
[95] ViewRowCache: removeReference, vr id = 3
################### after remove:
(5)成功Delete后,点击Commit

Console输出如下:
[96] OracleSQLBuilder: SAVEPOINT 'BO_SP'
################### before postChanges:
[97] OracleSQLBuilder Executing doEntitySelect on: JOBS (true)
[98] Built select: 'SELECT JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY FROM JOBS Jobs'
[99] Executing LOCK...SELECT JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY FROM JOBS Jobs WHERE JOB_ID=:1 FOR UPDATE NOWAIT
[100] Where binding param 1: 3344
################### doDML before delete:
[101] OracleSQLBuilder Executing, Lock 2 DML on: JOBS (Delete)
[102] DELETE buf Jobs>#u SQLStmtBufLen: 105, actual=37
[103] DELETE FROM JOBS Jobs WHERE JOB_ID=:1
[104] Where binding param 1: 3344
################### doDML after delete:
################### after postChanges:
################### before commit:
################### after commit:
[105] JobsView1 notify COMMIT ...
[106] EntityCache close prepared statement

4. 把删除操作变为修改操作
(1)重写remove方法和doDML方法

public void remove() {
setMinSalary(new Integer(-1));
setMaxSalary(new Integer(-1));
super.remove();
}

protected void doDML(int operation, TransactionEvent e) {
if (operation == DML_INSERT) {
System.out.println("################### doDML before insert:");
super.doDML(operation, e);
System.out.println("################### doDML after insert:");
} else if (operation == DML_UPDATE) {
System.out.println("################### doDML before update:");
super.doDML(operation, e);
System.out.println("################### doDML after update:");
} else if (operation == DML_DELETE) {
if (operation == DML_DELETE) {
operation = DML_UPDATE;
}
super.doDML(operation, e);
}
}

remove方法说明:这里必须把设置字段值的操作放到 super.remove();前面,否则运行时会抛出异常:“Attempt to access dead entity in Jobs, key=oracle.jbo.Key[123 ]"。
(2)运行AM,删除一条记录,并Commit
Console输出如下:
[81] QueryCollection: afterRemove(0)
[82] ViewRowCache: removeReference, vr id = 3
[83] OracleSQLBuilder: SAVEPOINT 'BO_SP'
################### before postChanges:
[84] OracleSQLBuilder Executing doEntitySelect on: JOBS (true)
[85] Built select: 'SELECT JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY FROM JOBS Jobs'
[86] Executing LOCK...SELECT JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY FROM JOBS Jobs WHERE JOB_ID=:1 FOR UPDATE NOWAIT
[87] Where binding param 1: 2232
[88] OracleSQLBuilder Executing, Lock 2 DML on: JOBS (Update)
[89] UPDATE buf Jobs>#u SQLStmtBufLen: 255, actual=64
[90] UPDATE JOBS Jobs SET MIN_SALARY=:1,MAX_SALARY=:2 WHERE JOB_ID=:3
[91] Update binding param 1: -1
[92] Update binding param 2: -1
[93] Where binding param 3: 2232
################### after postChanges:
################### before commit:
################### after commit:
[94] JobsView1 notify COMMIT ...
[95] EntityCache close prepared statement
查看数据库,被Delete的记录依然存在,只是MinSalary和MaxSalary字段的值为-1。

5. 运行页面form_crud.jsf
点击Delete,并确认提交后,发现数据被真的删除了,说明Delete Opertaion并没有调用remove方法。
从Console输出也能够看出来,因为没有打印出来自定义的语句,这不符合我的本来想法。
如果执行Delete Opertaion时没有调用remove方法,那remove方法就失去其意义了。
难道说,如果想调用remove方法,就必须通过程序明确调用EO的remove方法?比如:

public void deleteJob(String jobId) {
JobsImpl job = retrieveJobById(jobId);
if (job != null) {
job.remove();
try {
getTransaction().commit();
} catch (JboException ex) {
getTransaction().rollback();
throw ex;
}
}
}


Project 下载:ADF_Form_CRUD(CustomEO).7z

参考文献:
1. http://radio-weblogs.com/0118231/2003/07/28.html

没有评论: