Dorado 5 : 4.Dataset数据集对象 (T1)

在Web项目中,数据是贯穿始终的灵魂,所有操作的最终目的都是围绕数据来进行的。同样,在dorado中Dataset的存在具有十分重要的意义,它是dorado的核心概念。

Dataset简述

Dataset又称Dataset数据集对象,用来管理一组数据,其结构类似于关系型数据库中的表或视图,通常主要用于封装从业务逻辑层中获取的数据。在标准的dorado开发模式当中,Dataset的功能基本涵盖了对数据逻辑处理的各项要求。 开发人员可以利用Dataset来完成绝大部分的数据持久化、数据提取等的操作。
Dataset具有当前记录的概念,这一点不同于ArrayList和Vector。只要Dataset中有可见记录,当前记录就不可能是null,此时Dataset的大多数操作都针对当前记录的操作。例如:setString、getBoolean、deleteRecord等。
Dataset也可以管理不可见的记录。例如:被标记为已删除的记录。可以通过RecordIterator对象访问Dataset中的这一部分记录。
在dorado中常用的Dataset有7种类型,包括AutoSqlDataset、SqlDataset、FormDataset、DatasetReference、CustomDataset、DODataset、MarmotDataset等。
在服务器端,不同类型的Dataset会有不同的数据加载方式。而在客户端只有一种类型的Dataset,当用户在客户端操作Dataset时,它与服务器端Dataset的类型是没有关系的。在系统运行时,dorado只是根据Dataset的定义决定需要使用哪种类型的服务器端Dataset与客户端Dataset对象进行同步处理。

Dataset的结构

Dataset的结构类似于数据库中的二维表,其中含有Field列对象和Record记录对象用于规范和管理数据。

  • Field列对象

Field列对象在dorado中又称字段,可以理解为数据库表中的列。其中包含数据类型、列标题等。

  • BaseField

普通的字段,包含在dorado的内部,一般可以由dorado自动生成。

  • DummyField

临时字段,为编程及存放临时信息所用,不会作更新数据库或被转换为POJO对象,类似临时变量。

  • Record记录对象

Record记录对象在服务器端Dataset加载数据时或客户端执行记录插入操作时被创建。Record对象封装有状态信息,可标识每个Record对象在浏览器端被何种方式操作。

  • STATE_NONE

无状态。是Record的默认状态。

  • STATE_NEW

新增状态。执行插入记录操作时Record的初始状态。

  • STATE_INSERT

插入状态。对于新插入的记录对象,执行对其的校验确认动作后的状态。

  • STATE_MODIFIED

已更新状态或修改状态。修改某个Record对象值之后,执行对其的校验确认动作后的状态。

  • STATE_DELETE

删除状态。执行对该记录的删除操作后的状态。

记录指针

Dataset拥有记录指针概念。在Dataset中大量的Record对象以集合方式存在,对每个Record对象的访问可以通过记录指针的移动实现。
默认情况下,Dataset中的记录集存在时,记录指针会定位在第1条。在浏览器端,通过DataTable控件可以很清楚地看到,第1条记录高亮显示,而DataTable的记录指示器也指向第1条记录。
任何时候,当Dataset中存在记录集时,记录指针总是指向其中某条记录。

图13-11

  • 当前记录

当前记录指针所指向的记录对象。任何时候,执行Dataset的getCurrent()方法时,都会返回当前记录指针所指向的记录对象,如果指向的记录对象不存在,则返回null。

  • 移动记录

可以通过Dataset提供的方法执行对记录指针位置的移动。

  • move(int margin)

以当前记录为参考,移动指定的记录行数。参数margin是相对于当前记录的滚动行数,如果值小于0,则向前滚动。

  • moveNext()

移动到下一条记录,并将下一条记录作为当前记录。

  • movePrev()

移动到上一条记录,并将上一条记录作为当前记录。

  • moveFirst()

移动到记录集最顶端的记录,此时isFirst()返回true,当前记录为第1条记录。

  • moveLast()

移动到记录集最末端的记录,此时isLast()返回true,当前记录为最后1条记录。

  • isFirst

当记录指针指向的当前记录从第2条移动到第1条时,仍然返回false,此时再执行向前移动记录则返回true,即移动到第1条记录之前。此时当前记录为第1条记录。

  • isLast

当记录指针指向的当前记录从倒数第2条移动到倒数第1条(即最后1条)时,仍然返回false,此时再向后移动记录则返回true, 即移动到最后1条记录之后。此时当前记录为最后1条记录。

常用的方法和属性

在Dataset中有许多常用的方法和属性,并非每个属性或方法都属于所有类型的Dataset。并且,有些属性和方法只有在客户端的Dataset中才有意义。下面介绍在实际开发中常用的一些方法和属性。

  • flushData方法

flushData是Dataset提供的客户端方法。flushData方法的主要作用是重新从服务器端加载数据至Dataset中,最终填充至客户端当前的Dataset。执行此方法时Dataset中原有的记录将被全部清除。在客户端可以直接调用flushData()方法向服务器端发出请求。
因为是从服务器端请求加载数据,所以flushData方法会导致被请求重新加载数据的Dataset对象在服务器端的重构,并同时调用其所在的ViewModel实现类处于ViewModel.STATE_SERVICE状态时的相关初始化和加载数据的方法。

  • postRecord方法

postRecord方法是Dataset提供的客户端方法。当用户在客户端对Dataset对象执行插入新记录的操作时,新录入的数据需要被校验和确认是否合法,如果通过校验则记录对象的状态由NEW转成INSERT,并最终提交至服务器端。postRecord方法起到的作用是执行校验和确认动作,返回是否通过校验。

  • ParameterSet参数集

所有的Dataset对象都有ParameterSet参数集。Dataset中的参数集可以在客户端通过JavaScript编码dataset.parameters().setValue(key,value)或者采用【Dataset】—>【Parameters】—>【Insert】—>【Parameter】的方式创建参数对象。

图13-12
当参数集在浏览器端被新增参数对象,随着Dataset一起被提交至服务器端后,可以在服务器端取出该参数对象并处理。

  • MasterLink属性

通过JavaScript脚本编码或者新建Parameter对象为各参数对象赋值时,必须事先知道所要赋予并提交的参数值。而在具体的实际应用中,有些参数值通常是无法事先确定的。例如在主从表查询中,从表(Detail)的查询参数值来自于主表(Master)的查询结果,而主表(Master)的查询结果是无法事先预知的。对于这种情况,dorado提供了MasterLink属性实现动态赋值的方法。
某个Dataset在服务器端运行时,如果需要参数值而参数却没有被赋值时,Dataset会自动地检查MasterLink的设置。如果为MasterLink属性定义了属性值,Dataset就会从该属性值的配置中查找另一个Dataset的相关参数值,并且匹配到当前Dataset的参数集合中作为参数值提交。

Dataset的客户端事件

dorado的BRich Client提供了丰富的事件编程接口,开发人员可以通过这些事件接口对ViewModel进行定制和扩展。Dataset同样也提供了大量的事件编程接口供定制开发和扩展。
Dataset中常用的客户端事件有:

  • 记录滚动事件
  • beforeScroll

当记录将要滚动时,即当前记录将要被改变时触发(通常情况下Dataset的移动记录的方法,或DataPilot的记录滚动按钮以及DataTable的鼠标滚轮滚动都会触发记录的滚动事件)。通常情况下可在此处通过返回AbortException的方式阻止记录的滚动。例如:return new AbortException();

  • afterScroll

当记录滚动后,即当前记录改变后触发。

  • 记录新增事件
  • beforeInsert

当将要向Dataset插入新记录时触发该事件(通常情况下Dataset的inertRecord()方法,或DataPilot的新增按钮以及DataTable的Ctrl+Insert操作都会触发记录的新增事件)。可在此处通过返回AbortException的方式阻止记录的新增。

  • afterInert

向Dataset中插入新记录后触发该事件(通常情况下Dataset的inertRecord()方法,或DataPilot的新增按钮以及DataTable的Ctrl+Insert操作都会触发记录的新增事件)。

  • 记录修改事件
  • beforeChange

当Dataset的当前记录将要被修改时触发该事件(通常情况下Dataset或Record的setValue()方法,或通过绑定Dataset的数据控件修改其中的内部数据都会触发记录的修改事件)。可在此处通过返回AbortException的方式阻止记录的修改。

  • afterChange

当Dataset的当前记录被修改后触发该事件。

  • 记录删除事件
  • beforeDelete

当Dataset中的记录将要被删除时触发该事件(通常情况下Dataset的deleteRecord()方法,或DataPilot的删除按钮以及DataTable提供的Ctrl+Delete操作都会触发记录的删除事件)。可在此处通过返回AbortException的方式阻止记录的删除。

  • afterDelete

当Dataset中的记录被删除后触发该事件。

Dataset的监听器

Dataset的监听器用于监听Dataset中的各种事件,在某些系统中监听器也被称为回调机制。在AJAX应用中监听器的作用更像是一个服务器端的服务接口。随时为Dataset的各种动作提供服务。例如Dataset数据翻页或Dataset的数据保存时。都会触发监听器各种事件。
Dataset通过listener属性定义监听器对象,监听器可以实现的监听事件主要有:

  • 字段创建事件

当dataset执行createFields时触发的事件,在监听器中加入了两个事件接口。

  • beforeCreateFields

当Dataset将要自动创建所有字段之前触发的事件。即当调用Dataset.createFields()之前触发的事件。

  • afterCreateFields

当Dataset执行完自动创建所有字段之后触发的事件。即当调用Dataset.createFields()之后触发的事件。

  • 数据导入事件

当Dataset利用自身的配置信息从外部导入数据时发生。数据导入在AJAX技术是最常见的,也是服务器端编程的重要接口。开发人员可以在该处获取客户端的请求参数信息加以处理,并最终返回处理过的数据提供给客户端。
该事件比较典型的发生场景是当客户端执行flushData操作、主从表联动操作、数据树的延迟加载动作,联动下拉框操作等等,都会触发服务器端的数据加载动作。如果此时对产生数据导入事件的Dataset配置了监听器,则系统就会自动触发数据导入事件。

  • beforeLoadData

当Dataset将要装载数据之前触发的事件.即当调用Dataset.loadData()之前触发的事件。此方法的返回值用于通知Dataset是否要继续执行系统默认的loadData()操作。如果已经在此事件中为 Dataset定义好了所有的字段,可以返回一个false值终止执行系统默认的loadData()操作。

  • afterLoadData

当Dataset执行完装载数据之后触发的事件。即当调用Dataset.loadData()之后触发的事件。

  • 数据保存事件

与数据导入事件类似,数据集执行数据保存时触发的事件。

  • beforeUpdateData

当Dataset将要保存数据之前触发的事件。即当调用Dataset.update()之前触发的事件。
此方法的返回值用于通知Dataset是否要继续执行系统默认的update()操作。如果有其他需要处理的业务逻辑而不需要数据保存,可以返回一个false值终止系统默认的update()操作。

  • afterUpdateData

当Dataset执行完数据保存之后触发的事件。即当调用Dataset.update()之后触发的事件。

不同类型的Dataset

dorado拥有不同类型的Dataset对象满足各种开发需要,根据获取数据方式和用途的不同,Dataset大概可以分为7种。

  • SqlDataset

在SqlDataset中,开发人员可以自行编写一个十分复杂的用于查询的SQL语句来定义SqlDataset的sql属性。SqlDataset根据该属性获取数据库中的数据,并且在这个过程中SqlDataset本身可以充分利用dorado提供的方言机制实现高效率的数据查询。SqlDataset既可以通过配置使用也可以在服务器端编程使用。

  • AutoSqlDataset

AutoSqlDataset是一种通过向导定义方式获取Dataset内容的一种数据集。相比SqlDataset,AutoSqlDataset的定义更为简单和快捷 。AutoSqlDataset提供了对象式描述查询语句的方式,并增加了对SQL语句的直接支持,从而使AutoSqlDataset可以实现较为复杂的查询工作。另外AutoSqlDataset还提供了一些优异的特性,使开发人员更为方便的定义与实现查询工作,例如查询分页功能的自动处理机制,查寻条件的逃逸处理机制,查寻条件的复合匹配机制等。这样使得开发人员在实现业务需求时大部分的情况下都可以通过定义而不是手工编写SQL语句获取查询结果。AutoSqlDataset也提供了数据的持久化能力,很多情况下开发人员可以不写代码而通过Dataset直接将数据保存到数据库中。AutoSqlDataset也支持用服务器端编码创建,不过在一般情况下建议使用配置方式创建。

  • FormDataset

FormDataset最主要的功能是其自身的构造与Request的parameters相关。
该类继承覆盖了doLoad方法,在该方法内部利用Request对象构造Dataset。如当前页面的URL请求为formdatasetdemo.jsp?param1=&param2=&param3=,则当FormDataset在初始化的时候会自动根据Request的parameters创建相关的字段,分别为param1,param2,param3。FormDataset自动新增一条记录,将Request中parameters中的值作为FormDataset新增记录的值。FormDataset使用方比较简单,它通常并不被从后台加载数据,而用作接收客户端的输入数据。比如:查询的输入表单等。

  • DatasetReference

DatasetReference主要被使用在需要在其所在的ViewModel中引入Module数据坞中的公用Dataset。其数据也来自Module数据坞中的Dataset,DatasetReference的生命周期是Request,而其数据来源处Dataset的生命周期则可以通过scope和timeout设置,这意味着DatasetReference所引用的数据可能一直在服务器端缓存,这种情况下加载数据的效率是较高的。

  • CustomDataset

CustomDataset与FormDataset类似,不仅拥有FormDataset的功能,而且比FormDataset多了更多的属性,同时功能也更强大。实际上CustomDataset与SqlDataset,AutoSqlDataset的差别也并不大。在系统开发时配合POJO+Hibernate的方式(或其他ORM技术), CustomDataset几乎可以达到与SqlDataset和AutoSqlDataset类似的功能。
CustomDataset主要用在数据展现与数据提交的场合。较多地应用于整合一些持久层框架的场景中(如Hibernate,iBatis等)。利用自身的ObjectClazz、PageSize、PageIndex等属性以及Dataset提供的服务器端toDO()、fromDO()等方法,可以非常灵活地进行数据的展现和处理。

  • DODataset

DODataset的使用方式与CustomDataset基本一致,与之相比DODataset又多了contextAttribute属性和supportsPaging属性两个属性。
contextAttribute属性是用来设置与DODataset进行数据交换的上下文(如request)属性名。设定了此属性之后,DODataset会在执行加载数据时自动到上下文对象(如request)的该属性中寻找DO类型的数据。如果找到了相应的数据将自动尝试将其加载到DODataset中。在执行数据更新时DODataset会自动尝试将数据更新到上下文对象(如request)存储的数据集对象中。
supportsPaging属性指定了DODataset是否会自动根据pageSize和pageIndex属性的值确定数据的分页方式,默认值为false。设置属性值为true时,加载数据至DODataset后,设置pageSize和pageIndex属性可以实现DODataset的自动分页功能。由于是在内存中实现分页功能,为了保证性能,建议最好是数据量比较小的情况下使用(比如几十条),如果数据量比较大则不推荐。

  • MarmotDataset

MarmotDataset主要被用于更好的与spring框架集成,其目的在于可以与开发商原有业务架构中已经集成了spring框架的,或采用类似框架的系统架构实现无缝整合开发。MarmotDataset通常会与dorado提供的专门用于处理MarmotDataset的MarmotUpdateCommand以及MarmotRPCCommand对象配合使用。
与普通的Dataset的监听器不同,MarmotDataset可以将数据加载工作交给spring配置的bean来实现。这种方式可以很容易的利用spring本身强大的IOC、AOP等机制实现对数据加载工作的控制。同样使用MarmotDataset的数据提交或远程调用也是通过spring中配置的bean实现,这样就可以比较方便的利用spring中的事务管理机制。
在MarmotDataset中,有三个属性非常重要。DataProvider属性的主要作用是给MarmotDataset提供数据,其属性值一般是在spring中配置的bean的id;ObjectClazz属性的主要作用是告诉MarmotDataset需要处理的数据类型,其属性值一般是自定义的POJO;method属性主要用于实现方法分派,其属性值指定被调用的方法名。