Dojo Data Store——统一数据访问接口
原文地址:http://www.infoq.com/cn/articles/wq-dojo-data-store
无论在传统的桌面应用还是在主流的互联网应用中,数据始终占据着软件应用中的核心地位。当下,web2.0已经是一个让人们耳熟能详的词汇,而由此 带来的数据的开放与共享,引领我们走入了海量数据时代。在今天的互联网上,数据的交互几乎成为了我们的终极诉求,可随之而来的数据多样性,信息的分布式存 储及松耦合,以及数据量的几何级规模的膨胀也带来了数据组织上的难度的增大,与此同时,伴随着Ajax, RIA及面向服务的网络应用的发展,其所要求的客户端数据处理逻辑的复杂性不断增加,使得开发难度不断加大。出于简化数据处理逻辑,增加应用的可维护及可 扩展性的需求,目前流行的JavaScript框架也基本都会具有各自的数据处理模块或接口。本文的目的就是为了介绍Dojo的数据处理模 块:Dojo.data。作为Dojo的数据处理中间层,其主要的职责就是解析及管理由数据源传入的各种类型的数据,通过统一的数据访问与处理接口与数据 展现层(Dojo Widget)进行通讯,便于各个Widget的管理与程序的移植。
Dojo Data中的数据管理
在面向服务应用大行其道的今天,协调数据的多样性是开发互联网应用中不可避免的首要问题。我们常见的数据格式包括Json, XML, Csv等,作为数据处理的中间层,能够让用户以统一的接口连接不同的数据源是一个基本需求。在Dojo.data模块中,预定义了不同的 DataStore用于访问管理不同数据格式的数据源,而所有的DataStore都会实现相同的数据访问接口,这样就可以成功实现数据提供层与数据展现 层之间的松耦合。表1中列出了Dojo中部分已实现的各种不同的DataStore。
表1. Dojo中部分已实现的DataStore
DataStore | 描述 |
dojo.data.ItemFileReadStore | 用于JSON数据的只读的DataStore |
dojo.data.ItemFileWriteStore | 用于JSON数据的可读写的DataStore |
dojox.data.CsvStore | 用于CVS数据的只读的DataStore |
dojox.data.OpmlStore | 用于OPML(Outline Processor Markup Language)数据的只读的DataStore |
dojox.data.HtmlTableStore | 用于HTML table数据的只读的DataStore |
dojox.data.XmlStore | 用于XML数据的可读写的DataStore |
dojox.data.FlickrStore | 用于读取flickr.com提供的数据的只读的DataStore。是一个很好的web service相关的DataStore的示例 |
dojox.data.QueryReadStore | 用于读取由服务器端提供的JSON数据的只读的DataStore |
尽管读取的数据源多种多样,但在DataStore中,通过统一数据访问接口,对数据的组织管理是一致的。每条数据项都被作为一个item对象,其 中包含了一定的键(attribute)值(value)对用以对应数据条目中的各个属性值。下面以一段简单的JSON数据片段为例,来介绍这种对应关 系:
{
identifier: 'id',
label: 'name',
items: [
{ "id": "AF", "name":"Africa", "type":"continent",
"population":"900 million", "area": "30,221,532 sq km" },
{ "id": "AS", "name":"Asia", "type":"continent",
"population":"1 billion", "area": "25,428,192 sq km" }
]
}
在这段JSON数据中共有两条数据项(item),分别都包含有"id", "name", "type", "population"与"area"五个属性字段。
Dojo.data 组织架构
为了符合各种应用中对数据中间层的不同需求,Dojo.data包对数据访问处理接口进行了一定程度的划分,包括 read,write,identify,notifaction 等。各种DataStore可以根据其应用需求实现特定的接口。
表2. Dojo.data.api主要接口
Dojo.data主要接口 | 描述 |
Dojo.data.api.read | 提供读取数据项或者其属性值的功能,同时也支持对数据集的搜索,排序,和过滤。 |
Dojo.data.api.write | 提供创建,删除,更新数据项功能。 |
Dojo.data.api.identify | 提供基于唯一的标示符来定位和查询数据项的功能。 |
Dojo.data.api.notification | 提供当 datastore的数据项改变等事件发生时通知侦听器的功能。最基本的事件包括数据的创建,修改和删除等。这也是Dojo.data的一项很重要的功能,通过此接口可以将数据展现层与数据中间层更好的分离开来。 |
Dojo.data API简介
Read
数据的获取是数据中间层的核心,Dojo.data.Read接口为异步获取异构数据提供了很大的便利性和灵活性。在Read接口中,主要是通过异步方式进行数据的获取,同时也提供了数据的排序、分页、简单查询等基本功能的支持。
- fetch: function(/* Object */ keywordArgs)
fetch方法可以说是Dojo.data包的核心方法,它主要采用异步方法来获取数据。该方法接收一个键值对对象参数,用户可以通过对此参数中各个属性进行指定以获取特定的数据集合,如分页,简单查询过滤,排序等。以下是部分主要的参数属性介绍:
- onBegin与onComplete: fetch方法是采用异步的方式来进行数据的获取,用户可以通过onBegin与onComplete这两个参数指定fetch方法的数据获取回调函 数,onBegin在数据返回前会被调用一次,传入两个参数,分别为应返回数据集的条目数及此次fetch的request对象;而onComplete 方法是作为数据返回的回调函数,数据集作为第一个参数传入给该回调函数。
- start与count: 通常来说几乎所有的实际应用都会要求分页返回数据以提供更好的用户体验,start和count这两个属性就是为支持分页功能而实现的。start用于指定返回数据的起始索引(由0开始),而count则用于设置返回的数据条目数。
- query: 除了分页以外,按需返回特定的数据集也是一项重要功能,在Dojo.data中,这一功能则是通过query属性提供支持的。query的值一般可设置为 一个键值对对象,“键”应被设置为数据条目中的某项属性,而“值”则为条件指定。Dojo.data提供了精确匹配与模糊匹配(通配符:*为任意字符,? 为单个字符)两种方式对数据进行过滤,可以根据具体情况选择使用。
- sort:由于可能出现多个Widget使用同一个DataStore,数据集并不会以特定的序列进行存储,当需要进行排序时,可以通过 sort属性进行指定,DataStore则会相应的返回符合条件的数据集。sort 参数不仅指定了要排序的字段,而且还必须指定排序的顺序即升序还是降序。
dataStore.fetch({
// 设置获取数据的起始位置
start: 0,
// 设置获取数据的条目数
count: 25,
// 设置模糊过滤条件
query: {'name': *},
// 数据排序设定
sort: [{ attribute: 'name', descending: false }],
// 设置开始数据获取的回调函数
onBegin: function(size, requestObj){...},
// 设置数据获取完成后的回调函数
onComplete: function(items, requestObj){...},
// 设置数据获取失败后的回调函数
onError: function(error, requestObj){...}
}); - getValue: function(/*item*/item, /*attribute-name-string*/attribute, /*value?*/ defaultValue)
用于获取某个给定的数据项的某个属性值,如果该条数据不含有指定的属性,则返回一个指定的默认值。item参数为给定的数据项,attribute参数为指定的属性字段,defaultValue为可选参数。
var value = dataStore.getValue(item, 'name', 'no name');
- getAttributes: function(/* item */ item)
获取给定数据项的所有属性字段,返回值为一个数组。
Write
Dojo.data.Wirte接口主要提供了数据的更新功能API,包括创建、删除、更新数据。同 Read 接口类似,Write API 的设计目标也是屏蔽底层数据存储格式的差异,为用户提供统一的数据访问 API。借助这些 API,用户可以专注于业务层面的逻辑实现,而无需花费太多精力去关注底层数据的存储格式。
- newItem: function(/*Object?*/ keywordArgs, /*Object?*/ parentInfo)
在DataStore中新创建一个数据项。第一个参数为一个键值对对象,用于设定新创建的数据项,第二个参数为可选参数,当用户想将新创建的数据项作为某个已存在的数据项的子,则可以通过这个参数进行设定。具体应用请参照下面的小示例:
var euItem = {"id": "EU", "name":"Europe", "type":"continent", "children": [] }
// 新建数据项
dataStore.newItem(euItem);
// 新建子数据项
dataStore.newItem({"id": "GM", "name":"Germany", "type":"country"}, {parent: euItem, attribute: "children"}); - deleteItem: function(/*item*/ item)
在DataStore中删除指定的数据项。
- setValue: function(/*item*/ item, /*string*/ attribute, /*almost anything*/value)
更新某条给定数据项的某个属性值。
Notification
当DataStore中有数据更新时,相应的Notification中定义的监听函数就会被调用。使用过Dojo的读者可 能都会注意到,在Widget中一般不会有new、delete等其他JavaScript库控件中常见的API。这是因为Dojo data的设计是力求将数据层与表现层进行分割,对数据的操作都集中在数据层进行控制,而数据集的改变也能够自动的在应用控件上进行反映,这一功能就是当 DataStore在进行数据更新操作时,通过Notification接口的通知作用实现的。
- onNew: function(/*item*/ newItem, /*object?*/ parentInfo)
当DataStore中创建新数据项操作成功后被自动调用。newItem参数就是新创建的数据项对象,parentInfo是可选参数,用于描述新创建数据项的父数据项。
- onDelete: function(/*item*/ deletedItem)
当DataStore中删除某项数据项后被自动调用。deletedItem参数就是被删除的数据项对象。
- onSet: function(/*item*/ item, /*attribute-name-string*/ attribute, /*object | array*/ oldValue, /*object | array*/ newValue)
在DataStore的某项数据项被更新后进行调用。四个参数分别为数据项对象,被更新数据项属性,该数据的原有值以及更新后的值。
Identify
很多数据源都会为数据提供唯一的标识符,Dojo.data.Identify接口则提供了基于唯一标识符进行数据获取定位的API支持。
- fetchItemByIdentity: function(/*object*/ keywordArgs)
同Read接口中的fetch方法类似,此方法也是一个异步方法,用户需要在参数对象中指定数据项获取后的回调处理函数。 keywordArgs参数是一个键值对对象,主要需要包括两个属性,一个是要进行指定获取的数据项标识符identify,另一个则是回调处理函数 onItem。在指定identify的数据项获取成功后,onItem回调函数则会被自动调用,以处理后续操作。
dataStore.fetchItemByIdentity({
// 指定要进行获取的数据项的id
identity: "AS",
// 设定数据返回后的回调函数
onItem: function(item){…},
// 设定错误回调函数
onError: function(error){…}
}); - getIdentity: function(/*item */ item)
此方法用于获取给定数据项的标识符。
DataStore应用
一般来说,Dijit中的各个小部件都提供了对DataStore的支持,当我们在使用某个Widget来进行数据展现时,通常我们只需要根据数据 源的格式类型来选择好DataStore,然后在Widget声明中对DataStore进行指定就可以了。下面我们就通过DataGrid及 ComboBox作为数据展现UI,基于不同的数据格式为它们设置不同的DataStore。
以下是一份JSON数据:
data = {
identifier: 'id',
label: 'name',
items: [
{ "id": "AF", "name":"Africa", "type":"continent",
"population":"900 million", "area": "30,221,532 sq km" },
{ "id": "AS", "name":"Asia", "type":"continent",
"population":"1 billion", "area": "25,428,192 sq km" },
{ "id": "OC", "name":"Oceania", "type":"continent",
"population":"21 million", "area": "15,928,294 sq km" },
{ "id": "EU", "name":"Europe", "type":"continent",
"population":"56 million", "area": "25,928,294 sq km" },
{ "id": "NA", "name":"North America", "type":"continent",
"population":"100 million", "area": "90,928,294 sq km" },
{ "id": "SA", "name":"South America", "type":"continent",
"population":"102 million", "area": "78,928,294 sq km" },
{ "id": "AN", "name":"Antarctica", "type":"continent",
"population":"998", "area": "102,928,294 sq km" }
]};
在这里,我们采用比较简单的dojo.data.ItemFileReadStore:
var jsonStore = new dojo.data.ItemFileReadStore({data: data});
ItemFileReadStore比较适合于处理数据量较小的数据源,数据源可以是一个JSON文件或者象本例一样直接指定到客户端内存中的一组数据。当你使用更加大型的JSON数据集时,可以使用JsonRestStore,采用Rest服务来进行数据提供。
接下来,我们来声明一个DataGrid。在这里DataStore是通过”store”属性进行设置的。
<table jsid="grid" store="jsonStore" query="{name:’*'}" dojoType="dojox.grid.DataGrid" class="grid">
<thead>
<tr>
<th field="name" width="auto">Name</th>
<th field="population" width="auto">Population</th>
<th field="area" width="auto">Area</th>
</tr>
</thead>
</table>
生成的DataGrid如下图所示:
由于Dojo中对数据展现层与数据中间层的松耦合,同样一份数据源可以在不进行任何处理的情况下为多个Widget提供数据,而且由于数据的过滤、 排序、分页都是根据数据获取请求按需返回的,使用相同 DataStore的多个Widget间也不会产生冲突。下面我们就以同样的DataStore,为一个dijit.form.ComboBox提供数 据:
<input dojoType="dijit.form.ComboBox" store="jsonStore" searchAttr="name"></input>
在很多实际应用中,可能会使用不同的数据源,下面,我们采用不同的数据格式,以XmlStore来替换ItemFileReadStore。首先将JSON数据转换为XML数据格式:
<continents>
<continent>
<name>Africa</name>
<population>900 million</population>
<area>30,221,532 sq km</area>
</continent>
<continent>
<name>Asia</name>
<population>1 billion</population>
<area>25,428,192 sq km</area>
</continent>
<continent>
<name>Oceania</name>
<population>21 million</population>
<area>15,928,294 sq km</area>
</continent>
<continent>
<name>Europe</name>
<population>56 million</population>
<area>25,928,294 sq km</area>
</continent>
<continent>
<name>North America</name>
<population>100 million</population>
<area>90,928,294 sq km</area>
</continent>
<continent>
<name>South America</name>
<population>102 million</population>
<area>78,928,294 sq km</area>
</continent>
<continent>
<name>Antarctica</name>
<population>998</population>
<area>102,928,294 sq km</area>
</continent>
</continents>
XmlStore是一个客户端的数据存储器,用于读取XML数据源。它由Dojo官方提供并包含在DojoX子项目中。XmlStore为基本的 XML数据(一种常用的数据交换格式)提供读/写接口。XmlStore可以用于一般的XML文档,因此非常有用。存储器的设计是你可以通过覆盖其部分方 法来自定义读/写数据的行为。下面的示例给出了如何创建XmlStore并将其应用到Grid及ComboBox中:
var xmlStore = new dojox.data.XmlStore({
url: ‘continents.xml’,
label: ‘name’
}); <table jsid="grid" store="xmlStore" dojoType="dojox.grid.DataGrid" class="grid">
<thead>
<tr>
<th field="name" width="auto">Name</th>
<th field="population" width="auto">Population</th>
<th field="area" width="auto">Area</th>
</tr>
</thead>
</table> <input dojoType="dijit.form.ComboBox" store="xmlStore" searchAttr="name">
我们几乎不需要修改关于Grid和ComboBox的任何代码,就能让它们继续工作。唯一需要做的改动,就是声明一个数据源,并将它设置为grid的输入。我们不需要操心任何关于数据获取、解析、以及管理的事情,数据存储器的API做了所有的工作。
可以看出,作为数据中间层,Dojo.data通过优秀的API设计充分达成了数据展现层与数据管理层之间的松耦合,同时统一的数据访问接口使得对多种数据格式的应用以及程序移植都带来了相当大的便利性。
参考资料
Dojo Data Store——统一数据访问接口的更多相关文章
- Razor视图引擎布局 Razor视图引擎的基本概念与法语 SQL Server Mobile 和 .NET 数据访问接口之间的数据类型映射 binary 和 varbinary datetime 和 smalldatetime float 和 real
Razor视图引擎布局 不需要像过去aspx一样,使用.Master文件,而是统一使用.cshtml 或 .vbhtml文件.但文件名一般以 _开头,这样做文件不会当做View显示出来 使用@Re ...
- SQL Server 提供的各种数据访问接口
在创建SQL Server的链接服务器时,可以看到有如下几种访问接口,其中我们常用的只有1.3.4.6.其中4是安装Oracle客户端才会出现的接口,3.6是由于我电脑上装了2008R2和2012两个 ...
- Enterprise Solution 生成实体数据访问接口与实现类型 Code Smith 6.5 模板文件下载
数据库表定义为SalesOrder,用LLBL Gen Pro生成的实体定义是SalesOrderEntity,再用Code Smith生成的数据读写接口是ISalesOrderManager,最后是 ...
- 第四章 Spring.Net 如何管理您的类___统一资源访问接口
在前面章节有童鞋提到过 关于配置文件 Objects.xml 路径的相关问题,这些东西是 IResource 接口的一些内容,接下来就详细介绍一下 IResource 接口. IResource 接口 ...
- vue-elem-配置静态模拟数据访问接口
使用本地mock数据模拟真实数据配置 static/data.json dev.server.js中 var app=express();之后添加以下代码, var appData=require(' ...
- SQL Server Mobile 和 .NET 数据访问接口之间的数据类型映射
.NET 数据类型 SQL Server Mobile 数据类型 binary varbinary boolean bit byte tinyint byte[] varbinary dateti ...
- Spring Boot的数据访问:CrudRepository接口的使用
示例 使用CrudRepository接口访问数据 创建一个新的Maven项目,命名为crudrepositorytest.按照Maven项目的规范,在src/main/下新建一个名为resource ...
- Yii的学习(2)--数据访问对象 (DAO)
摘自Yii官网:http://www.yiiframework.com/doc/guide/1.1/zh_cn/database.dao Yii提供了强大的数据库编程支持.Yii数据访问对象(DAO) ...
- 数据库访问接口(ODBC、OLE DB、ADO)
最近在学C#的数据库编程,对于数据库接口技术这块的知识一直比较模糊,网上查了不少资料,看了几天还是朦朦胧胧的,只能做些笔记再研究了. 我们都知道,“数据库”是指一组相关信息的集合,最早的计算机应用之一 ...
随机推荐
- Oracle数据库自动启动Shell脚本
为了保证Oracle在下次系统重启后,能自动启动服务,这里我们可以通过一个Shell脚步来实现这个功能.假定脚步名称为/app/oracle/oraclestart.sh,其内容如下: #!/bi ...
- 控制input标签中只能输入数字以及小数点后两位
js 代码如下: /* 控制input标签中只能输入数字 和小数点后两位 */ function checkNum(obj) { //检查是否是非数字值 if (isNaN(obj.value)) { ...
- 使用guava进行对字符串的加锁
java的synchronized关键字是堆某对象加锁,但是我们当需要对某个字符串加锁怎么办 比如对同一个订单只能有一个操作,但是对其他订单的操作不影响 使用 guava包下的 Interner 类 ...
- zabbix3.0 安装Tips
原文转自:http://www.cnblogs.com/tae44/p/4812190.html#3270843 此处只能留空,否则,提示安装无法进行!!
- C# mvc DropDownList选中状态无效情况分析
情况: DropDownList控件使用List<SelectListItem>()设置下拉选项和默认值.当控件的Name和后台的ViewBag(或ViewData)的Key重复,会导致选 ...
- h5整理--详解css的相对定位和绝对定位
浏览器默认状态下position的属性默认值是static也就是没有定位,元素出现在正常的文档流中,这个时候给元素设置的left,right.bottom.top这些偏移属性是没有效果的,不会生效: ...
- Windows安装mxnet
code { white-space: pre } div.sourceCode { } table.sourceCode,tr.sourceCode,td.lineNumbers,td.source ...
- eval回显变量
eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令.该命令适用于那些一次扫描无法实现其功能的变量. 一个应用场景如下: export path="/home/bin/" ...
- Android框架之AndroidAnnotations基础
一:开源网址 https://github.com/excilys/androidannotations/wiki 二:AndroidAnnotation特点 (1)依赖注入 可以注入 views, ...
- IIS 的一些配置记录
1.日志分析: URL:http://www.cnblogs.com/fish-li/p/3139366.html2.性能监视: 执行 perfmon.msc ,右键添加counter,添加web s ...