当使用到了marmotUpdateCommand来计算绑定的dataset中一共修改了多少条记录时,而这个dataset中的记录是通过其他控件的操作赋值的,这时其实已经修改了dataset的记录,但是如果修改的是多条记录的话,需要使用的dataset遍历方式需要是如下的 方法一,方法一在遍历的时候移动了当前记录,而方法二没有。<2010-10-20>
如何高效遍历Dataset
遍历一个Dataset中的数据主要有以下两种方式:
方法一
datasetX.moveFirst();
while (!datasetX.isLast()) {
... ... ...
datasetX.moveNext();
}
l 方法二
var record = datasetX.getFirstRecord();
while (record != null) {
... ... ...
record = record.getNextRecord();
}
如无特殊需要,我们推荐使用第二种方法完成对Dataset的遍历。这两种遍历方式的区别在于,第一种遍历方式是通过不断的改变Dataset的当前记录来完成遍历操作的,而第二种遍历方式在遍历的过程中并不会改变Dataset的当前记录。如果此时有任何数据敏感控件绑定在Dataset上,那么,改变Dataset的当前记录将会引起数据敏感控件的刷新动作。如果Dataset中有n条记录,在默认情况下,以第一种方式进行遍历将至少引起相关的数据敏感控件刷新n次,并且当遍历操作结束之后Dataset的当前记录应该总是最后一条记录。
另外,如果被遍历的Dataset是主从绑定关系中的主Dataset。那么直接使用第一种遍历方式将会更加危险,其下的从Dataset可能会随着主Dataset当前记录的改变不断的执行数据加载的动作。数据加载是一种比控件刷新更加耗时的操作。
很多时候,我们使用Dataset遍历是为了修改其中的每一条记录。在这种情况下,如果仅仅是使用此处第二种遍历方式,还远没有达到效率最佳化的目标。此时一定要结合3.4.4中介绍的disableControls()和enableControls()才能得到更好的运行效果。
实测数据:
以两种方式对一个包含2000条记录的Dataset进行遍历。实测环境的CPU为INTER Pentium(R) 1.73G。
l 方法一的耗时为0.256秒。(在进行此方法的测试时我们使用了3.4.4中介绍的disableControls()和enableControls()关闭了数据控件的刷新功能,否则速度将慢得无法忍受)
l 方法二的耗时为0.047秒。
由此可见,两种方式间有接近一个数量级的性能差异。方法二的优势非常明显。
disableControls()和enableControls()
Dataset的disableControls()方法和enableControls()方法大概是Dorado开发中最常用的优化技巧了。这个方法非常容易使用,而获取的效果也非常显著,他常常可以将一段代码的执行速度提高好几倍甚至更多。
disableControls()表示暂时禁用Dataset的绑定关系,即暂时禁止Dataset向绑定的数据敏感控件发送任何消息,这样数据敏感控件就不会随着Dataset的变化而自动刷新的。enableControls()则正好相反,表示重新允许Dataset向绑定的数据敏感控件发送消息。
disableControls()和enableControls()往往会跟Dataset.refreshControls()方法一起配置使用。refreshControls()的作用是通知所有与改Dataset绑定的数据敏感控件立即进行数据刷新。
假设我们现在要编写一段代码将Dataset中每一条记录的status字段的值设置为completed。未经优化的代码可能是这样的:
var record = datasetX.getFirstRecord();
while (record != null) {
record.setValue("status", "completed");
record = record.getNextRecord();
}
假设DatasetX中有n条记录,那么,进行一次这样的遍历将导致相关的数据敏感控件被刷新n次。其实这n次刷新中的前n-1次都是没有任何意义的。
利用disableControls()、enableControls()结合refreshControls()优化之后的代码可能是这样的:
datasetX.disableControls();
try {
var record = datasetX.getFirstRecord();
while (record != null) {
record.setValue("status", "completed");
record = record.getNextRecord();
}
}
finally {
datasetX.enableControls();
datasetX.refreshControls();
}
这样在执行循环的过程中数据敏感控件完全不会刷新,直到循环结束之后,手工调用refreshControls()通知数据敏感控件进行数据刷新。整个操作将需要进行这一次刷新。
disableControls()、enableControls()并不总是用在循环操作中,只要是针对Dataset的批量操作都考虑使用这种优化技巧。例如下面的这段用于数据复制的未优化代码:
dataset1.setValue("id", "0001");
dataset1.setValue("name", dataset2.getValue("cname"));
dataset1.setValue("sex", (dataset2.getValue("sex"))?"M":"F");
dataset1.setValue("addr", dataset2.getValue("address"));
dataset1.setValue("tel", dataset2.getValue("telephone"));
dataset1.setValue("email", dataset2.getValue("email"));
dataset1.setValue("web", dataset2.getValue("web"));
dataset1.setValue("cmnt", dataset2.getValue("comment"));
我们同样可以使用disableControls()和enableControls()对其进行优化,优化后的代码可能如下:
datasetX.disableControls();
try {
dataset1.setValue("id", "0001");
dataset1.setValue("name", dataset2.getValue("cname"));
dataset1.setValue("sex", (dataset2.getValue("sex"))?"M":"F");
dataset1.setValue("addr", dataset2.getValue("address"));
dataset1.setValue("tel", dataset2.getValue("telephone"));
dataset1.setValue("email", dataset2.getValue("email"));
dataset1.setValue("web", dataset2.getValue("web"));
dataset1.setValue("cmnt", dataset2.getValue("comment"));
}
finally {
datasetX.enableControls();
datasetX.refreshControls();
}
使用disableControls()和enableControls()时还应该注意这样一个细节,这两个方法的运行机制类似于计数器,而不是通常理解的开关。如果对一个Dataset连续执行两次disableControls()方法,那么也必须再执行两次enableControls()才能重新启用绑定关系,即回复Dataset向数据敏感控件发送消息。
下面的代码可能有助于您理解disableControls()和enableControls()的运行机制:
// 此时绑定可用
datasetX.disableControls();
// 此时绑定被禁用
datasetX.disableControls();
try {
// 此时绑定被禁用
}
finally {
datasetX.enableControls();
// 此时绑定被禁用
datasetX.enableControls();
// 此时绑定可用
}
实测数据:
对一个包含50条记录的Dataset进行遍历,并在遍历的过程中修改每一条记录中的5个字段值。
实测环境的CPU为INTER Pentium(R) 1.73G。需要注意的是,此处的测试结果与界面的复杂度密切相关,测试的主要目的是确认未优化代码与优化代码间的性能差异。越是复杂的界面其差异越明显,所以具体的时间值本身参考价值并不大。
l 未经优化的测试代码,其耗时为2.016秒。
var record=dataset1.getFirstRecord();
while (record!=null) {
record.setValue("field1", "123");
record.setValue("field2", "234");
record.setValue("field3", "345");
record.setValue("field4", "456");
record.setValue("field5", "567");
record.post();
record=record.getNextRecord();
}
l 优化后的测试代码,其耗时为0.25秒。
dataset1.disableControls();
try {
var record=dataset1.getFirstRecord();
while (record!=null) {
record.setValue("field1", "123");
record.setValue("field2", "234");
record.setValue("field3", "345");
record.setValue("field4", "456");
record.setValue("field5", "567");
record.post();
record=record.getNextRecord();
}
}
finally {
dataset1.enableControls();
dataset1.refreshControls();
}