2012年6月29日星期五

ADF_152:AM使用指南之二:Nested AM与Root AM之间的Transaction关系

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

在实际应用中,为了达到逻辑重用的目的,会使用嵌套的AM。
在Root AM和Nested AM中都有各自的VO,在一个页面中,可能同时用到了不同AM的不同的VO,那么当一个AM提交时,另一个AM是否也会提交呢?
其实,这个问题的产生来自于一个客户的真实情况:
在一个页面中,有多个Tab页签,每个Tab页签中都一个表单和保存按钮。
用户可以选择修改Tab页签中的表单,于是就出现了这种情况:
用户修改了某个Tab页签中的表单,没有马上提交,接着修改另一个Tab页签中的表单,并点击这个Tab页签中的保存按钮,结果发现前一个页签中的修改也被成功提交了。

为了更加清楚阐述这个问题,我做了一个实验。

实验步骤主要如下:

1. 创建并定制化AppModule,包含JobVO和EmployeeVO。
增加3个方法,代码如下:

public void createJob() {
JobsViewImpl jobVO = (JobsViewImpl)getJobsView1();
JobsViewRowImpl newJob = (JobsViewRowImpl)jobVO.createRow();
jobVO.insertRow(newJob);
newJob.setJobId("Oracle");
newJob.setJobTitle("CEO");
newJob.setMinSalary(new Integer(10000));
newJob.setMaxSalary(new Integer(50000));
getTransaction().commit();
}

public void deleteJob() {
JobsViewImpl jobVO = (JobsViewImpl)getJobsView1();
JobsViewRowImpl currentJob = (JobsViewRowImpl)jobVO.getCurrentRow();
jobVO.removeCurrentRow();
getTransaction().commit();
}

public void saveEmployee() {
getTransaction().commit();
}


2. 创建并定制化NestedAppModule,包含JobVO。
(1)创建



(2)定制化
增加2个方法,代码和AppModule前2个方法相同,略。

3. 把NestedAppModule加入到AppModule中。
(1)

(2)完成后的Data Control

4. 创建页面,内容如下:
(1)拖放root AM DC中的JobView1和EmployeeView1,都选择Form。
(2)为Job Form 添加两个Button: Create和Delete。代码如下:
public String rootAMCreate_action() {
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("AppModuleDataControl");
AppModuleImpl service = (AppModuleImpl)am;
service.createJob();
return null;
}

public String rootAMDelete_action() {
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("AppModuleDataControl");
AppModuleImpl service = (AppModuleImpl)am;
service.deleteJob();
return null;
}
(3)为Employee Form 添加一个Button: Save。代码如下:
public String rootAMSave_action() {
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("AppModuleDataControl");
AppModuleImpl service = (AppModuleImpl)am;
service.saveEmployee();
return null;
}

(4)拖放root AM DC中的NestedAppModule1中的JobView1,选择Form。

(5)同样也为这个Job Form 添加两个Button: Create和Delete。代码如下:
public String nestedAMCreate_action() {
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("AppModuleDataControl");
AppModuleImpl service = (AppModuleImpl)am;
NestedAppModuleImpl nestedService = (NestedAppModuleImpl)service.getNestedAppModule1();
nestedService.createJob();
return null;
}

public String nestedAMDelete_action() {
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("AppModuleDataControl");
AppModuleImpl service = (AppModuleImpl)am;
NestedAppModuleImpl nestedService = (NestedAppModuleImpl)service.getNestedAppModule1();
nestedService.deleteJob();
return null;
}

(6)直接拖放Nested AM DC中的JobView1,选择Form。
(7)同样也为这个Job Form 添加两个Button: Create和Delete。代码如下:
public String topNestedAMCreate_action() {
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("NestedAppModuleDataControl");
NestedAppModuleImpl service = (NestedAppModuleImpl)am;
service.createJob();
return null;
}

public String topNestedAMDelete_action() {
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("NestedAppModuleDataControl");
NestedAppModuleImpl service = (NestedAppModuleImpl)am;
service.deleteJob();
return null;
}

5. 运行

为了说明问题,我测试了如下场景:

(1)修改Employee表单的某个属性,但并不点击Save按钮提交,而是点击Nested AM inside Root AM中的Job表单的Create按钮提交。
现象:被修改的Employee 表单的属性被成功提交入库。
解释:Employee VO属于Root AM,选择的Job VO属于Nested AM inside Root AM,它们使用同一个Transaction。
因此当修改前一个表单后,虽然提交的是另一个表单,前一个表单的数据也被提交了。

(2)修改Nested AM inside Root AM中的Job表单的某个属性,但并不点击Create/Delete按钮提交,而是点击Root AM中的Employee表单的Save按钮提交。
现象:被修改的Job 表单的属性被成功提交入库。
解释:同(1)。

(3)修改Employee表单 的某个属性,但并不点击Save按钮提交,而是点击 Nested AM outside Root AM中的Job表单的Create按钮提交。
现象:被修改的Employee 表单的属性并没有被写入数据库。
解释:Employee VO属于Root AM,选择的Job VO属于Nested AM outside Root AM,相当于是一个Root AM,二者是平行AM的关系,各自管理各自的Transaction。
当修改前一个表单后,而提交的是另一个表单,前一个表单的数据并没有被提交。

(4)修改Nested AM outside Root AM中的Job表单的某个属性,但并不点击Create/Delete按钮提交,而是点击Root AM中的Employee表单的Save按钮提交。
现象:被修改的Job 表单的属性并没有被写入数据库。
解释:同(3)。

6. 结论
(1)Nested AM与Root AM 使用的是同一个Transaction,都是Root AM中的Transaction,无论使用哪个AM提交,另一个AM中的VO也会被提交。
(2)多个Root AM之间的Transaction互不干涉,各自管理自己的。
(3)所以,要想避免提交本不想提交的表单,该表单所对应的VO的AM必须是Root AM。

7. 补充说明
以上提交方法都是使用getTransaction().commit(); 。
经过进一步测试,使用DataControl提供的Commit操作(拖放到页面上),实验结果和上述测试相同。

Project 下载:ADF_NestedAM_Transaction.7z

没有评论: