Extjs学习笔记之九 数据模型(上)

Extjs的数据模型分为以下几个部分:

数据记录 Record
数据集合中的一个条记录,包括数据的定义和值。相当于实体类。
数据代理 Proxy
用来获取数据的代理。相当于Datasource。
数据解析器 DataReader
负责将Proxy获取的数据解析出来传换成Record并存入Store中。相当于C#的DataReader。
数据集 Store
一个保存数据的集合,类似于C#的Datatable。
Extjs3的Proxy较以前版本有了一些变动,资料很少,而且官方文档上相当简练,以至于一个完整的例子都没有…… 我尽力理解……

1. 数据记录
一条数据记录一般是有多个字段组成的。字段由Ext.data.Field类定义。Field的配置项很丰富,使我们有足够的信息在弱类型的语言中处理我们的数据,主要有:

name:字段名;defaultValue:默认值;type:数据类型,可以是string,int,float,boolean,date和auto(默认)。先介绍这么多,其余的在具体用到的时候再介绍。

要建立一个数据记录类(注意不是具体一条数据),可以使用Ext.data.Record.create方法,这个方法接受一个数组的Field类的配置项,返回一个构造函数。看一个例子:


代码如下:

<script type="text/javascript">
// create a Record constructor from a description of the fields
var TopicRecord = Ext.data.Record.create([ // creates a subclass of Ext.data.Record
{name: 'title' },
{ name: 'author', allowBlank: false },
{ name: 'totalPosts', type: 'int' },
{ name: 'lastPost',type: 'date' },
// In the simplest case, if no properties other than name are required,
// a field definition may consist of just a String for the field name.
'signature'
]);

// create Record instance
var myNewRecord = new TopicRecord(
{
title: 'Do my job please',
author: 'noobie',
totalPosts: 1,
lastPost: new Date(),
signature: ''
},
id // optionally specify the id of the record otherwise one is auto-assigned
);
alert(myNewRecord.get('author'));
</script>

这里演示的仅仅是Record最基本的功能:定义字段和存取数据。Record还可以和Store一起,由Store跟踪Record的变化情况。就如C#的DataTable一样,可以跟踪其内部的DataRow变更的情况。Extjs几乎把前台开发变成了后台。这些内容等介绍Store的时候再介绍。

2.数据代理
Ext.data.DataProxy是数据代理的抽象基类,实现了DataProxy的通用公共接口。DataProxy的最重要的通用方法就是doRequest,执行这个方法之后将从各种具体的数据源读取数据。继承自DataProxy的具体Proxy类有:

2.1 HttpProxy

这是最常用的proxy,通过一个http请求从远程服务器获取数据。HttpProxy最重要的配置项就是配置获取数据的url。HttpProxy不仅仅支持获取数据,它支持对数据的CRUD操作。DataProxy的api属性就是用来配置这4种操作对应的url的。如果不配置,就采用HttpProxy的url属性。例如:


代码如下:

api: {
read: '/controller/load',
create : '/controller/new', // Server MUST return idProperty of new record

save : '/controller/update',
destroy : '/controller/destroy_action'
}

注意,extjs的官方文档这里相当含糊不清:

四个操作中的第一个到底是read还是load???
配置好api后,就可以执行doRequest方法,doRequest方法的参数比较复杂:

doRequest( String action, Ext.data.Record/Ext.data.Record[] rs, Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg )含义如下:action:表示执行的是哪种操作,可以是 create,read,update,destroy的一种。rs: 看了半天也没发现这个参数有什么用…… 看源代码发现其中出现了这样的表达式 url+rs.id,这个或许是为MVC架构的程序更好的构建url用的?直接忽略它,设为null即可。params:这个对象里边的属性:值对会作为post/get的参数传到服务器,非常有用。

reader: DataReader,将服务器返回的数据解析成Record的数组。下面会有更详细的解释。

callback:当读取到服务器数据之后执行的函数。这个函数接受三个参数,分别是: r Ext.Record[],服务器端返回的经过reader的数组。这是官方的说法,实际测试下来似乎只有当action是read的时候才是这样,下面有介绍;options:就是arg参数的值。success:是否成功的标致,bool,这个也是服务器端返回的。

scope:作用域

arg:一些附加的参数,会被传到callback的options参数中。

下面我们来完成一个例子,利用httpproxy完成基本的CRUD操作。先看服务器端代码:


代码如下:

<%@ WebHandler Language="C#" Class="dataproxy" %>

using System;
using System.Web;
using System.Collections.Generic;

public class dataproxy : IHttpHandler {
static List<Student> db = new List<Student>();
static dataproxy()
{
db.Add(new Student { Id = "1", Name = "Li", Telephone = "1232" });
db.Add(new Student { Id = "2", Name = "Wang", Telephone = "5568" });
db.Add(new Student { Id = "3", Name = "Chen", Telephone = "23516" });
db.Add(new Student { Id = "4", Name = "Zhu", Telephone = "45134" });
db.Add(new Student { Id = "5", Name = "Zhou", Telephone = "3455" });
}
public void ProcessRequest (HttpContext context) {
string id = context.Request.Params["id"];
string action=context.Request.Params["action"];
string result = "{success:false}";
if (action == "create")
{
}
else if (action == "read")
{
foreach (Student stu in db)
{
if (stu.Id == id)
{
result = "{success:true,r:[['" + stu.Id + "','" + stu.Name + "','" + stu.Telephone + "']]}";
break;
}
}
}
else if (action == "update")
{
}
else if (action == "delete")
{
}
context.Response.ContentType = "text/plain";
context.Response.Write(result);
}

public bool IsReusable {
get {
return false;
}
}

class Student
{
string id;
public string Id
{
get { return id; }
set { id = value; }
}
string name;
public string Name
{
get { return name; }
set { name = value; }
}
string telephone;

public string Telephone
{
get { return telephone; }
set { telephone = value; }
}
}
}

我们用一个静态的List来模仿数据库。在处理函数中分别应对4种情况。上面仅实现了read的代码,返回一个数组,因为我们最终客户端采用ArrayReader来解析数据。服务器端的代码没什么好解释的,很简单,再看客户端的:


代码如下:

<head>
<title>Data Proxy</title>
<link rel="Stylesheet" type="text/css" href="ext-3.1.0/resources/css/ext-all.css" />
<script type="text/javascript" src="ext-3.1.0/adapter/ext/ext-base-debug.js"></script>
<script type="text/javascript" src="ext-3.1.0/ext-all-debug.js"></script>
<script type="text/javascript" src="ext-3.1.0/src/locale/ext-lang-zh_CN.js"></script>
<script type="text/javascript">
var Student = Ext.data.Record.create(['id', 'Name', 'Telephone']);
var arrayReader = new Ext.data.ArrayReader({
root: 'r', idIndex: 0, fields: Student });
var httpProxy = new Ext.data.HttpProxy({
url: 'dataproxy.ashx',
api: {
read: 'dataproxy.ashx?action=read',
create: 'dataproxy.ashx?action=create',
update: 'dataproxy.ashx?action=update',
destroy: 'dataproxy.ashx?action=delete'
}
});
Ext.onReady(function() {
var form = new Ext.FormPanel({
renderTo: document.body,
height: 160,
width: 400,
frame: true,
labelSeparator: ':',
labelWidth: 60,
labelAlign: 'right',
defaultType: 'textfield',
items: [
{ fieldLabel: 'ID',
id: 'ID'
},
{ fieldLabel: 'Name',
id: 'Name'
},
{ fieldLabel: 'Telephone',
id: 'Telephone'
}
],
buttons: [{ text: 'Read', handler: function() {
httpProxy.doRequest('read', null, { id: form.getForm().findField('ID').getValue() }, arrayReader,
function(r, option, success) {
if (option.arrayData.success) {
var res = r.records[0];
Ext.Msg.alert('Result From Server', res.get('id') + ' ' + res.get('Name')
+' '+ res.get('Telephone'));
}
else {
Ext.Msg.alert('Result','Did not find.');
}

},this,arrayReader);
}
},
{ text: 'Delete' }, { text: 'Update' }, { text: 'Create'}]
})
});
</script>
</head>

这里有些东西要解释下,首先是定义了一个Student的Record,这个和服务器端的代码是一致的。然后定义了ArrayReader,ArrayReader是读取数组内的数据,数据格式参考服务器端的代码,它有一个root属性非常重要,指定的是读取json数据中哪个属性的值(这个值是一个数组的字面量).idIndex也是必须指定的,它标志着哪个字段是主键。fields就好理解了,读取的Record的字段。数组里边的顺序要和Record的字段顺序对应,否则可以通过Record的mapping属性来指定,例如: {name:'Telephone',mapping:4}就表示读取数组中第4个数值放到Telephone字段中。 下面就是定义httpProxy,设置好api。然后我们创建一个表单:

添加4个按钮。先为Read按钮写上处理函数:doRequest的一个参数是'read',第二个参数是null,因为我不懂它有什么用;第三个参数把要查询的ID的值传给服务器,第四个参数是一个reader,第五个参数callback很重要,我们在这里处理服务器的返回值。注意,我在最后一个参数设置为arrayReader,于是这个函数的option参数的值实际上就是arrayReader。我为什么要这样做呢,一来是做个演示,最后一个参数有什么用,二来是因为ArrayReader比较古怪,注意它没有公开的successProperty配置项,也就是说它无法判断服务器返回的success属性,也就是这个callback的success参数永远是undefined!我一开始以为是我服务器端的代码不对,后来debug进源代码,发现它确实不处理这个success属性。或许ArrayReader设计的本意就不是用在这个环境里的。不过作为演示,那就这样用吧。其实它不处理success参数我们自己还是可以处理的。arrayReader内部有个arrayData属性,它是一个解析好的json对象,如果返回的json字符串中有success属性那么这个对象也有success属性,这样我们就可以获得服务器的返回值,同理,也可以处理服务器返回的任何数据。当然,这种用法是文档上没有的,仅供演示。这个callback的第一个参数,要特别注意,文档上说是Record[],不过实际上它是一个对象,它的record属性才是Record[]。我只能说extjs这部分的文档很糟糕。幸好这部分的代码是很不错的,有兴趣的朋友可以调试进去看看,以便有更深刻的理解。好了,万事俱备,点击下Read按钮,结果出来了:

此文暂告一段落,其他几个操作原理上类似的,突然发现,如果单纯的用这个例子来演示似乎不太合适。因为Delete和Update服务器端都不需要返回什么数据,而doRequest强制要求用一个DataReader来解析返回的数据,很不方便。或许在操作表格型的数据的时候doRequest的其他方法才有用武之地。针对单个对象的CRUD,可以直接采用更底层的Ext.ajax方法(另文介绍),或者利用表单的方法来处理。

本文只是对Extjs的数据模型的功能和原理做一简单的介绍,在实际中如何高效的组织代码和在服务器与客户端间传递数据是一个另外的话题。Extjs还是很灵活的,客户端和服务器端的通信契约还是可以让程序员自己决定。

太长了…转下篇…

(0)

相关推荐

  • Extjs学习笔记之九 数据模型(上)

    Extjs的数据模型分为以下几个部分: 数据记录 Record 数据集合中的一个条记录,包括数据的定义和值.相当于实体类. 数据代理 Proxy 用来获取数据的代理.相当于Datasource. 数据解析器 DataReader 负责将Proxy获取的数据解析出来传换成Record并存入Store中.相当于C#的DataReader. 数据集 Store 一个保存数据的集合,类似于C#的Datatable. Extjs3的Proxy较以前版本有了一些变动,资料很少,而且官方文档上相当简练,以至于

  • ExtJs 学习笔记 Ext.Panle Ext.TabPanel Ext.Viewport第1/3页

    通过此文能学习到如下内容 1.创建一个简单的面板 Ext.Panel 2.制作一个可以拖动的面板 Ext.Panel 3 .使用选项卡面板 3.使用Ext.Viewport搭一个简单布局(用一个小例子来总结本文所有内容) 面板是ExtJs控件的基础,很多控件都是在面板的基础上扩展的,或者他会与其他控件之间有关系. 面板由一个工具栏.一个底部工具栏.面板头部.面板尾部和面板主区域几个部分组成.面本类中还提供了面板展开.关闭等功能.并提供了一些可重用的工具按钮让我们灵活的控制面板.面板可以放入其他任

  • extjs 学习笔记(一) 一些基础知识

    我在项目中已经频繁使用了jquery,这次主要是学习使用extjs,但现有的教程基本都是针对2.0的,而且后台用到的语言也很少是.net平台下的C#,所以我打算针对3.0版,后台使用C#,记录下自己的学习过程,希望能和志同道合的朋友一起探讨,共同进步. extjs的官方网站是http://www.extjs.com,目前最高版本是3.0.2,但是只有3.0.0的才没有任何下载限制,可以点击这里下载3.0版的.下载来的压缩包里边包含压缩后的extjs库,调试时用到的库,具有可读性的源代码,文档和例

  • extjs 学习笔记(三) 最基本的grid

    jquery在这方面则正好相反,它的UI都以插件形式提供,可以需要什么就引用什么,所以非常小巧灵活,但由于插件往往是由不同的人或者团队来提供,界面和接口往往就不那么一致.反正是各有千秋吧. 今天学习extjs中的grid,它可以说是功能强大,无出其右,只有你想不到的,没有它做不到的,呵呵,好像是有点夸张了.好,不说废话了,我们就从最简单的grid开始,一步步来看看extjs给我们提供的grid究竟给我们提供了哪些功能. 一个grid包括一些行和列,在extjs里边,列由Ext.grid.Colu

  • Extjs学习笔记之八 继承和事件基础

    这里接口的意思是Observable实际上起了一个抽象类的作用,Extjs中有大量的组件都是继承自这个类的.这个类提供了一些基本的方法比如addEvents,addlistener,fireEvent等等. 本文暂时不介绍如何使用extjs的组件响应事件,而是介绍Extjs的事件的一些实现原理.整个Extjs框架都是以一种面向对象的方式开发的,所以理解Javascript中的继承也很重要.我前面的一篇文章 补点基础:Javascript中的类和闭包 也是为这篇做准备.另外,博客园内还有一个写的很

  • Extjs学习笔记之四 工具栏和菜单

    ToolBar的使用很简单,关键是向ToolBar上面添加内容,默认地ToolBar添加的是Button,不过实际上可以向Toolbar添加任意的组件.下面是一个例子: 复制代码 代码如下: <script type="text/javascript"> Ext.onReady(function() { var tb = new Ext.Toolbar({ renderTo: document.body, width: 600, height: 100, items: [

  • ExtJs 学习笔记 Hello World!第1/2页

    在了解基础后,可能会用Ext+ajax开发一个简单的小项目,会一点一滴的讲解项目开发过程,希望能给大家带来收获!因为我本人也在学习这个框架,所以对文章有什么建议请提出,这样可能会让我学到更多. 看到这幅图,你可能认为是某个软件,或者是Flash.Flex.silverlight等等,但这是javascript+Css实现的. 在看这样式与效果,如果加在自己的项目里,用户视觉与操作的体验应该会很爽吧. 还有更多的特效就不一一截图了.      下面开始说一下这个组件,ExtJs是一个不错的Ajax

  • Extjs学习笔记之二 初识Extjs之Form

    Extjs中的表单组件是Ext.form.BasicForm,不过最简单最常用的是Ext.form.FormPanel控件,它继承自Panel,具有一定的界面显示控制能力,它其中包含着一个BasicForm对象,用来执行向服务器提交,加载等动作.Extjs也对常用的html表单项进行了封装,提供了一些额外的功能,比如数据验证.实际使用的时候只要向FormPanel中添加这些表单项即可.常见的表单项有,TextField,NumberField,Radio,CheckBox等. 下面通过一个例子来

  • Extjs学习笔记之七 布局

    Extjs Layout Browser . Extjs3.1.0 版本支持17种,下面挑一些重要的简要的说明一下,要看效果,去上面给的链接,不再贴图了.给Panel设置Layout的方法是一样的,就是设置Panel的Layout配置项.1. AbsoluteLayout 可以通过Panel内部组件的决定位置来布局.通过x,y来指定. 示例用法: 复制代码 代码如下: new Ext.Panel({ layout: 'absolute', title: 'AbsuluteLayout', ren

  • Extjs学习笔记之六 面版

    Extjs为我们封装好了Panel,Panel具有统一的标题头,面板体,面板底部,还可以自由的添加工具栏等.另外,extjs中还有丰富的布局,可以用来布局Panel.这种方式很像Java的Swing. Panel可以嵌套,可以作为整个页面的框架,也可以作为一个小功能区.前几篇文中用到的FormPanel就是继承自Panel类的. 下面的例子展示了一个较为完整的Panel,主要是设置工具栏: 复制代码 代码如下: <html xmlns="http://www.w3.org/1999/xht

随机推荐