Nova PhoneGap框架 第四章 本地数据库
我一直想把EntityFramework(简称EF)的那一套搬过来,应用于HTML5 SQLite。 幸运的是,我几乎做到了,有些功能无法完成的那是因为SQLite本身不支持。至少从现在已经完成的功能来看,我们几乎可以像EF那样去操作数据库。
在我们这个框架中,所有对数据库的访问都封装在了命名空间"nova.data"下面。其下主要包括了以下类:
- nova.data.DbContext
- nova.data.Entity
- nova.data.Repository
- nova.data.Queryable
下面我将逐一详细阐述。
4.1 nova.data.DbContext
这个类相当于是数据库的定义。我们定义的数据库的类都应该继承自这个类。下面让我们先来看个例子吧。

这段代码定义了一个数据库,但实际上里面只有一张表,关于表的定义我会在下一节中详述。这里唯一的一张表就是"this.targets", 类型是"nova.data.Repository",相当于EF中的DbSet,实现的都是仓储模式。
请注意上面的第6行代码,nova.data.DbContext构造函数的第2个参数是版本号(字符串)。这个版本号的神奇之处在于,当它改变的时候,那么在初始化数据库的时候(通常在index.html),整个数据库就会重新创建。如果你希望数据库在重新创建的时候能够带一些初始数据,那么你可以覆写initData方法。
让我们把目光再次投向第10行代码。上面我说了,这一行代码是在这个数据库中定义了一张表。如果还想添加更多的表怎么办呢?对于聪明的你来讲一定不成问题。只需要在这个at.domain.AtDbContext下增加一些属性,并且这些属性的类型都是nova.data.Repository。值得一提的是,repository的第一个参数是一个构造函数,并且类型必须继承自nova.data.Entity。具体的关于repository个entity的定义,我会在后面的内容中详细阐述。这里你只需知道如何定义一个数据库,如何往数据库中添加/删除/更新表。
4.2 nova.data.Repository
这个类相当于EF中的DbSet,跟nova.data.DbContext一起实现了仓储模式。所谓仓储模式,就是说任何对repository的增加/删除/更新操作都只有在调用了DbContext.saveChanges之后才会生效。我们这个框架中提供的数据访问也是这样一种模式,如此你便可以同时提交多条数据更改了,而不是每一次更改都要调用一次数据库。
这个类相当于EF中的DbSet,主要用于定义表。其第一个参数是实体类的构造函数,实体类需继承自nova.data.Entity, 第2个参数是字符串,及数据库中表的名字。
这个类下面有很多方法,我就不一一赘述了。发个截图吧,相信从方法的定义大概看得出是做什么的:

这个类实际我一直想着改造下的,那就是让它继承自nova.data.Queryable. 不过现在这样用着也满足需求,也挺方便。
这个类有个已知的BUG,会在本章末尾阐述。
4.3 nova.data.Entity
我在设计这个类的时候,我也试着模仿EF中的CodeFirst模式的代码。就是说每一个字段的数据类型在定义这个实体类的代码中体现,幸运的是我几乎实现了这样的功能。只要你在定义实体类的时候,给每一个属性指定一个初始值,那么在创建数据库的时候,就会根据这个初始值来指定数据类型。目前支持的数据类型有:integer, decimal,string, date,boolean。如下面的代码:

在我们的框架下开发应用程序,所有的本地数据库实体类都应该继承nova.data.Entity。
这个类只有一个属性integer id,这也是SQLite数据库每一张表默认都会带的字段。因此,在你的数据库实体类的定义中,不应该再定义id这个字段了。除了这个id属性,这个基类还定义了一些方法,主要是用于处理数据类型的。
这个类的另一个强大之处在于,以Target实体类为例,当你同时往数据库插入了多条target记录,并调用了dbContext.saveChanges方法时,每一个target的id会得到更新。这个特性也是模仿EF的,因为我们在使用EF的过程中发现这个特性实在太有用了。相信你在使用我们框架的过程中也会喜欢这个特性的。
4.4 nova.data.Queryable
这个类是模仿Linq中的IQueryable的,其工作原理也是和IQueryable类似。请看下面这行代码:
db.targets.where(“price >= 10”).where(“price < 20”).orderBy(“category”).thenBy(“name”).toArray(callback).
如果你熟悉Linq,那么这行代码你一定不会陌生。是的,我们的框架就实现了这样的功能。上面这行代码,在调用toArray之前,每一个查询/排序条件都没有提交到数据库,而是放在了内存当中,只有当调用了toArray时,才会执行数据库的查询。
请注意上面这行代码的第一个where,这个where方法实际上是repository中定义的,但返回的却是queryable,而后面的where和orderBy等都是queryable的实例方法。这正是模仿Linq设计的巧妙之处。
这个类的其他方法都比较一目了然了,就贴个截图吧:

4.5 常用例子
前面我把我们框架中对于本地数据库访问的每一个成员都做了详细的介绍,但如果你对JS面相对象或者EF不那么熟悉的话,可能还是看得有些云里雾里。好吧,下面我就贴一些常用的例子,相信这些例子一定能让你领略到这个框架的独特魅力。
4.5.1 定义数据库
先上代码:

这段代码只定义了一个targets表,你当然可以增加更多的表,只需要把第3行代码复制几份,然后改改名字就可以了。
4.5.2 定义实体类
先上代码:

这里定义了一个Target类,还有很多个实例方法,看上去跟普通的类没有什么区别,唯一的区别就是继承自nova.data.Entity.
4.5.3 查询

4.5.4 插入

4.5.5 更新

4.5.6 删除

4.6 已知问题
目前有1个问题无法解决。
当同时执行批量插入、批量更新、批量删除的时候会报错。因此,如果你想同时执行这些批量操作的话,那么应该让一种批量操作完成之后再执行另一个批量操作。
Nova PhoneGap框架 第四章 本地数据库的更多相关文章
- Nova PhoneGap框架 第五章 文件结构
一个好的项目架构必然有着合理的文件结构,如果一个项目的文件组织混乱,那么可以断言一定是项目架构有问题. 合理的文件结构能够帮你更清晰的管理你的文件,并且当需要添加新的文件的时候,你的程序员很清楚应该加 ...
- Nova PhoneGap框架 第七章 设备事件处理
我们的框架包含了几种设备事件的处理,目的是为了让我们的程序员更容易的完成代码.这些事件包括:回退键(Android)和横竖屏切换事件. 7.1 Android回退键 首先来说说回退键的事件处理.当用户 ...
- Nova PhoneGap框架 第三章 页面
页面在项目架构中是一个很重要的概念,它让我们能够将一个功能复杂的项目拆分成一个一个功能比较独立的小区域,这极大的提高了代码的可读性和可维护性. 在我们这个框架中,一个页面由JS和HTML两部分组成,首 ...
- Nova PhoneGap框架 第六章 使用Mock
在我们的框架中引入了一个很重要的设计,那就是使用Mock. 这里的mock是指cordova.mock.js文件,它模拟了PhoneGap(Cordova)的API,从而可以在浏览器中运行测试我们的程 ...
- Nova PhoneGap框架 第一章 前言
Nova PhoneGap Framework诞生于2012年11月,从第一个版本的发布到现在,这个框架经历了多个项目的考验.一直以来我们也持续更新这个框架,使其不断完善.到现在,这个框架已比较稳定了 ...
- Nova PhoneGap框架 第二章 理解index.html
跟绝大多数PhoneGap程序一样,Index.html是程序的入口.这个页面应该完成应用程序的初始化工作. 首先,让我们来看看这个页面通常都长什么样子: 下面我将一一解释这个页面都做了哪些初始化工作 ...
- Nova PhoneGap框架 总结
Nova PhoneGap Framework 是完全针对PhoneGap应用程序量身定做的,在这个框架下开发的应用程序很容易实现高质量的代码,很容易让程序拥有很好的性能和用户体验. 在经历了多个项目 ...
- Nova PhoneGap框架 第八章 滚动条
你可能会疑惑为什么滚动条这么常见的功能会在这里单独列出,但如果你有过PhoneGap开发经验的话,你就会发现要在Android 2.3 里面实现滚动条那真不是一件容易的事. 8.1 概述 目前主流的P ...
- Nova PhoneGap框架 第九章 控件
我们的框架中也提供了一些常用的控件,这些控件大多都依赖于我们的框架,也正是在我们的框架下才使得实现这些控件的变得更简单.但是我们的框架是不依赖与这些控件的,如果你用不上这些控件,你完全可以把相关的代码 ...
随机推荐
- Android中用TextView显示大量文字的方法
最近学习Android中,试着实现一个简单的显示新闻Demo的时候,遇到了一个问题:一条新闻的内容文字很多,放在TextView上面超出屏幕了,怎么破? 查了一下资料,找到了两种方法实现: 1. 只用 ...
- Cocos2d-x 生成真正的随机数
关于随机数 cocos2d-x 定义了一个宏 CCRANDOM_0_1 生成的是 [0, 1] 之间的值 因此,要生成 [0-100] 之间的数 CCRANDOM_0_1 * 100 生成 [ ...
- UWP学习记录12-应用到应用的通信
UWP学习记录12-应用到应用的通信 1.应用间通信 “共享”合约是用户可以在应用之间快速交换数据的一种方式. 例如,用户可能希望使用社交网络应用与其好友共享网页,或者将链接保存在笔记应用中以供日后参 ...
- UWP学习记录1-开端
UWP学习记录1-开端 1.背景 针对不同基础的人,学习的路线自然是不同的.这篇文章记录的是我个人的学习路线,或者说笔记.我对自己的技术状态的定义是: A.有很好的windows平台编程基础: B.有 ...
- Java 之 I/O流
1.流 a.分类:①字节流:InputStream.OutputStream ②字符流:Reader.Writer b.选择:①判断是 输入 还是 输出 (站在程序的立场上) ②判断是 字节 还是 字 ...
- 如何找出标有"App Store 精华","Essentials"的所有软件?
如何找出标有"App Store 精华","Essentials"的所有软件? 中国区: +"App Store 精华" site:http ...
- Tween Animation---Scale渐变尺寸缩放动画
博主都是自己把代码测试过了才给大家分享的 在res/创建一个anim文件夹用来保存动画属性的xml 新建一个scale.xml <?xml version="1.0" enc ...
- 数据库sqlite 存储图片
SQLite可以存储 BLOB(binary large object,二进制大对象)格式数据,利用它可以在安卓应用开发中存储图片资源. 这里先讲下,怎样把数据从数据库中取出,并显示在imagView ...
- Visual Studio 2013执行项目报错:HTTP 错误 500.22
转至:http://www.codingwhy.com/410.html 具体报错 HTTP 错误 500.22 - Internal Server Error 检测到在集成的托管管道模式下不适用的 ...
- PHP注册与登录【2】用户注册
注册页面 reg.html 负责收集用户填写的注册信息.教程里只列出关键的代码片段,完整的代码附在本节最后. 注册表单 <fieldset> <legend>用户注册</ ...