OAF VO初始化分析

目录

第一部分 插入新行前的初始化

1 仅插入型VO的初始化

2 插入查询VO的初始化

第二部分 执行查询前的初始化

1 避免无条件查询

2 避免多余的查询

 

正文

第一部分 插入新行前的初始化

在处理插入初始化之前,我们必须确定一件事情,就是当前我们要处理的这个VO,它是只用作插入操作呢,还是即用作插入又用作查询操作。比如一个EmployeeCreateVO,这个VO仅仅在创建新员工的页面使用,不用做其他用途,那么我们认为它是一个只做插入操作的VO,反之,它就是一个即查询又插入的VO.理清楚这一点,对合理初始化VO很重要。

1仅插入型的VO的初始化

我们可以利用如下代码:

//检查VO是否有行,如果有行了,我们就不用执行括号里的语句了。vo.getFetchedRowCount()是检查当前缓存中VO的行数,包括新插入的行,它不执行数据库查询,仅仅检查内存中已经取出来的行。如VO已经被插入过行了,那么getFetchedRowCount肯定大于0,就无需再调用setMaxFetchSize了

if (vo.getFetchedRowCount() == 0) {

//此方法是设置VO的每次查询行数的上限,但是如果参数为0的话,此方法会设置mPreparedForExecution标识为TRUE。这个标识是OAViewObjectImpl的一个成员变量,表示VO是否准备好执行查询,初始值是FALSE。当VO执行了executeQuery()之后,该标识值也会被设为TRUE。

vo.setMaxFetchSize(0);

}

// 执行插入操作

Row row = vo.createRow();

vo.insertRow(row);

//遵循代码标准M69,在所有新插入的行后立即将起设置为STATUS_INITIALIZED状态,让此行处于脱管状态,不参与事务提交,不参与验证,直到在页面上对这行数据进行更新,然后OA框架自动把状态设回为STATUS_NEW,以重新参与事务和验证。

row.setNewRowState(Row.STATUS_INITIALIZED);

有时候我们会遇到这个错误:“违反了 OA 钝化结构编码标准。未正确准备全名为EmployeeAM.EmployeeFullVO1 的视图对象以供插入行。必须先调用视图对象中的setMaxFetchSize(0) 或executeQuery()(或最终执行视图对象查询的任何等效方法),然后才能插入新行。”

我估计是OAF框架在遇到插入行的时候,会检查当前VO有没有行,如果没有行,会检查在这句代码前面是否执行了executeQuery()或setMaxFetchedSize(0)语句(而不是检查mPreparedForExecution的值是否为TRUE),如果没有执行这样的语句,那么就报告违反钝化编码标准。当然这只是我的个人猜测,仅供参考。

对于只包含瞬时属性的VO,为了避免OAF中的一些已知的BUG,我们在对其进行初始化的时候最好像下面这样编写代码:

if (vo.getFetchedRowCount() == 0) {

vo.setMaxFetchSize(0);

vo.executeQuery();

... // Insert rows into the view object.

}

2带数据库查询的VO的初始化

首先,我们必须注意,在这种既用于查询又用于插入的VO情况下,我们必须先执行executeQuery(),然后再insertRow(),否则会导致一些钝化上的问题。

提示1:

总的来说,尽量为“创建**”或“插入**”型页面单独创建一个VO,比如单独创建一个创建员工的VO,EmployeeCreateVO.

提示2:

如果实在需要插入和查询或更新都公用一个VO,那么在插入前,应该给executeQuery加上条件。

if (!vo.isExecuted()){

vo.executeQuery();

// 或者调用vo.initQuery(..),以便根据你自己WHERE条件进行查询。

}

Row row=vo.createRow()

…其他初始化操作

注意:根据我个人经验,由于mPreparedForExecution标识变量并不会在rollback()后变为false,会造成未执行executeQuery()就进行insertRow()操作,那么OA框架就会报告“违反了OA 钝化结构编码标准。未正确准备全名为 EmployeeAM.EmployeeFullVO1的视图对象以供插入行。必须先调用视图对象中的 setMaxFetchSize(0) 或executeQuery()(或最终执行视图对象查询的任何等效方法),然后才能插入新行。”,所以在进行插入操作前,通过vo.isPreparedForExecution来作为判断条件不是最好的选择,可以选择用vo.isExecuted来代替。

第二部分 执行查询前的初始化

1避免无条件查询

一般情况下,我们可以使用下面的方法来避免无条件执行查询操作

if (!vo.isPreparedForExecution()) {//带条件执行查询操作

vo.executeQuery();

// 或者调用vo.initQuery(..),以便根据你自己WHERE条件进行查询。

}

无条件执行查询操作会导致一些事务状态的丢失,比如,对瞬时属性(transient view objectattributes)数据的更新会丢失,VO的current Row和currentRange会被重设。这也就从一定解释了“翻页后在有删除确认对话框的页面中无法删除行的案例”,具体参考我的另一篇文章《翻页后在有删除确认对话框的页面中无法删除行的案例》。

但是,有几种情况你不应该给查询加上条件:

1.你的页面是只读的,你不在乎VO的事务状态,你只希望每次渲染页面的时候都能看到数据库中的最新数据。

2.如果这个查询是在processFormRequest中调用的,例如,页面上有一个“GO”按钮,希望点击的时候查询出满足我需要的数据,那么这个时候也不要给他加上面的条件。因此,我们可以这样理解,上面的“带条件执行查询操作”仅用于在processRequest中对页面包含的VO的数据进行初始化操作。

3.加了这个条件后,在保持同一个AM的范围内,这个vo只被查询一次,以后不会再被查询,如果想重新执行查询,得到最新的数据,那么需要释放AM。

对于下钻页面(Drilldown TargetPage),比如搜索结果页面中点击员工姓名下钻到员工的详细信息,我们也不能依赖于isPreparedForExecution的判断,它太容易返回true了,以至于我们的查询得不到执行,我们更喜欢用vo.findByKey()这个方法,这个方法是根据VO下面的EO主键来查询,首先会检查缓存中有没有这条数据,没有才去执行数据库查询。注意,下钻页面的VO和搜索页面的VO最好不要使用同一个,以免下钻后,影响搜索页面的状态。

public void initDetails(Number employeeNumber){

EmployeeFullVOImpl vo = getEmployeeFullVO1();

Number[] keys = { employeeNumber};

Row[] rows = vo.findByKey(new Key(keys), 1);

// findByKey不会改变currentRow指针,所以需要我们手动去更改,否则页面上不会显示值。

if ((rows != null) &&(rows.length > 0)) {

vo.setCurrentRow(rows[0]);

} } // end initDetails()

2避免多余查询

涉及个性化,暂不讨论

 

上一篇:VO、DTO、DO、PO的概念、区别和用处


下一篇:项目启动报错:For input string: ""