在上一篇多样化实现Windows Phone 7本地数据库访问<1>采用两种方式Effproze和SQlite来验证Window Phone 7访问本地数据库.验证结论是可行的. 获得圆友及时反馈固然也发现一些细节上问题. 例如Effproze利用文件/内存模式 找不到指定的硬盘上数据库文件. Sqlite中支持Windows Phone 7 API没有相关文档. 以及SQlite建立后相似Effproze找不到指定存储文件等?相似这些问题 正在寻找和验证相关解决方案 稍后我会专门整理出一篇文章来详细说明. 本篇将继续验证Windows Phone 7访问本地数据库其余方式-Windows Phone DBhtml
<1>初识Windows Phone DBsql
其实看到Windows Phone DB[如下简称WPDB]很偶然机会.当时我正在研究另一家英国移动软件开发集成商本身作的开源数据库方式实现对WP7本地数据库访问.[详细见Windows Phone 7 gets open source database]时遇见WPDB的. 一个群组UK-Grouper 的DVP向我推荐Windows Phone DB.数据库
WPDB是利用Silverlight的独立存储[IsolatedStorage]机制为WP7访问数据库加以支持. 目前的版本只是针对开发人员. 使用简单. 开源. 其实它内部存储数据的实质就是利用IsolatedStorage. Silverlight的IsolatedStorage是一种相似Cookie的静态存储机制.能够将一些基本类型(String,Int)的信息甚至是自定义类型序列化后的静态存储于客户端文件中.windows
独立存储[IsolatedStorage]是一个局部信任机制. 什么叫局部? 当你建立一个Silverlight应用程序时会在硬盘上建立相应独立的存储区域. 这里面独立是相对于不一样Silverlight Project而言的. 固然若是应用程序中存在多个程序集[Project],那么存储空间在这多个程序集之间是共享的.dom
Silverlight限制了客户端Silverlight应用程序不能访问所有的文件系统,只能经过独立存储机制提供虚拟文件系统,访问数据流对象. 这样一来相似咱们Application 有了本身一块硬盘空间同样.独立存储空间内就能够放置任意类型的文件. XML /.txt等. 4版本中空间大小也是能够控制的. 更多资源请参考.Introduce IsolatedStorage MSDN 由此也能看出Silverlight也涵盖WP7平常开发 固然还有Silverlight能作还不止这些 以下图:Silverlight 涵盖图异步
<2>Windows Phone DB给咱们带来什么?ide
先不着急回答这个问题.WPDB是开源的 你在能够在CodePlex上下载它相关源码:函数
DownLoad on the CodePlex: Windows Phone DB[×××]工具
下载完源码用VS工具打开.预览整个Solutions:源码分析
Solutions中包含两个项目: 第一个为WPDB的源码项目 下面是对WPDB测试项目. 两者关系是测试项目对源码项目采起了引用. 先无论那么多运行起来看看效果:
页面只有一个Run tests按钮. 点击后运行提示Test Completed 测试完成 咱们来看Button按钮下事件下代码的调用:[注释是本身添加的]
- private void RunTests_Click(object sender, RoutedEventArgs e)
- {
- //获取测试项
- foreach (var item in ResultPanel.Children)
- {
- if (item is TextBlock)
- {
- ((TextBlock)item).Foreground = new SolidColorBrush(Colors.White);
- }
- }
- CreateDBTest();//建立DataBase
- CreateTableTest();//Create Table
- SaveTest();//Save Config
- SaveSingleTableTest();//保存单表
- OpenTest();//打开数据库
- AddRangeTest();//添加一个范围数据[20条]
- RemoveRangeTest();
- RemoveRangeConditionTest();
- SaveFailsTest();//保存记录
- SaveWithEncryptionTest();//保存加密后数据-[看来还考虑加密]
- OpenWithEncryptionTest();//打开机密数据
- SelectConditionTest();
- LazyLoadingTest();//还有延迟加载-[很意外啊]
- AddRowToExistingTableTest();//添加一行数据库
- AddRowToExistingTableTestLazyLoad();
- DatabaseExists();//关闭数据库连接
- //测试完成提示
- MessageBox.Show("Test completed", "Silverlight Phone Database", MessageBoxButton.OK);
- }
由上面代码很明显可以看出, 方法包含操做也就是咱们对数据库基本平常操做. WPDB彻底建立一套本身的API[其实内部封装就是一个Silverlight 类库],这点和Effproze 在WP7访问方式彻底不一样. Effproze的API彻底参考ADO.NET复制一个版本. SQlite则也是本身建立一套API.幸运的是此次咱们可以看到WPDB的源码. 先无论大致方法中操做实现. 咱们在回过头看看WPDB源码结构 分析以下:
如上分析可见.WPDB底层数据存储的实现 主要涉及到: DataBase/TAble的CRUD操做, 存储数据的加密和解密, 操做Exception异常自定义封装, IsolatedStorage数据存储以及文件流之间格式转换,Linq操做数据格式的支持,数据延迟加载等各个方面.从上源码分析来看. 这个WPDB实现整体来讲仍是比较简单的.不难理解.若是你以为这些功能不能知足你的需求. 彻底能够本身在如上代码添加更多的功能.
下面来看看对DataBase和Table表基本操做 我如今要建立一个PersionDB数据库 库中新建一个Persion表并添加 10条数据 如何实现: 建立DataBase:
- public static Database CreateDatabase(string databaseName, string password)
- {
- //若是存在抛出异常
- if (DoesDatabaseExists(databaseName))
- {
- throw new DatabaseExistsException(string.Format(DatabaseResources.DatabaseExistsExceptionText, databaseName));
- }
- //new一个DataBase新实例.
- //参数为:DataBaseName[数据库名称] password-[访问密码] false-[默认不采用延迟加载]
- return new Database(databaseName, password, false);
- }
建立先判断数据库是否存在, 而后new 一个Database实例看一下DataBase构造函数:
- private Database(string databaseName, string password, bool useLazyLoading)
- {
- //以下所有类DataBase封装属性
- _databaseName = databaseName;//数据库名称
- _password = password;//数据存储加密的密码-[注明:加密和解密都须要密码]
- _useLazyLoading = useLazyLoading;//是否启用延迟加载
- //封装了一个Collection 来存储当前DataBase下全部的Table表
- _tables = new ReadOnlyCollection<ITable>(new List<ITable>());
- _loadedTables = new Dictionary<Type, bool>();
- }
构造函数中封装DAtabase基本属性, 其中有必要说一下ReadOnlyCollection<ITable> 它其实目的是在Database对象建立一个Collection集合来存储表结构. 里面表结构实现是父类接口ITable.有了DataBase咱们建立一个Persion表:
- //建立库 [调用代码]
- Database.DeleteDatabase("test");
- Database db = Database.CreateDatabase("test");
- //建立相应表
- db.CreateTable<Person>();
建立表CreateTable方法定义:
- public void CreateTable<T>()
- {
- //判断表是否存在
- if (DoesTableExists(typeof(T)))
- {
- throw new DatabaseExistsException(string.Format(DatabaseResources.TableExistsExceptionText, typeof(T).FullName));
- }
- else
- {
- //奥 尽然这种写法 已经利用定义Collection定义好List大小Size 难道也直接考虑到List性能
- List<ITable> tables = new List<ITable>(_tables);
- //建立表 其实就是New 一个Table实例 指定Table的名称和访问密码
- tables.Add(SilverlightPhoneDatabase.Table<T>.CreateTable(_databaseName, _password));
- //建立成功后 把这个新建的表添加指定的数据库中
- _tables = new ReadOnlyCollection<ITable>(tables);
- }
- }
建立表同时也与表实例类型关联. 这是咱们须要定义一个Persion实体类[源码附有下载]. 把新建的TAble表添加到Database表存储集合中, 实现与数据库的关联. 有了表和数据库 快速插入10条记录: 数据插入操做:
- private void SaveTest()
- {
- //建立库和表
- Database.DeleteDatabase("test");
- Database db = Database.CreateDatabase("test");
- db.CreateTable<Person>();
- //数据库表存在状况下
- if (db.Table<Person>() != null)
- {
- for (int i = 0; i < 10; i++)
- {
- //添加数据 NewRandomPerson返回一个随机的实体类Persion
- db.Table<Person>().Add(NewRandomPerson());
- }
- //保存数据
- db.Save();
- this.SaveDBLabel.Foreground = new SolidColorBrush(Colors.Green);
- }
- else
- {
- this.SaveDBLabel.Foreground = new SolidColorBrush(Colors.Red);
- }
- }
数据添加到DAtaBase对象下属性ReadOnlyCollection<ITable> Tables集合中,db.Save数据保存在源码重写成两个方法: 下面保存全部的数据库和全部表到独立存储空间文件上:
- public void Save()
- {
- try
- {
- //建立应用程序类型独立存储
- using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
- {
- //删除存储文件 一个数据库对应一个存储文件
- if (store.FileExists(_databaseName))
- {
- store.DeleteFile(_databaseName);
- }
- //建立存储文件
- using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_databaseName, FileMode.OpenOrCreate, store))
- {
- //把数据库内容Database 写成文件流方式保存
- WriteDatabaseToStream(stream);
- stream.Close();
- }
- }
- foreach (var item in Tables)
- {
- //延迟加载方式
- if (_useLazyLoading)
- {
- if (_loadedTables[item.RowType])
- { item.Save(); }
- }
- else
- { item.Save(); }
- }
- }
- catch (Exception ex)
- {
- throw new SaveException(ex);
- }
- }
看到了吧这就是数据真正存储到独立存储空间上文件里方法. 注意独立存储Isolated Storage根据应用程序做用域不一样分为应用程序和站点两种类型. 使用时分别用不一样对象建立,当前采用应用程序方式.
存储时利用数据库名称做为文件名, 对应关系为 一个数据库对一个独立存储文件. 数据库库保存细节是把数据库内容及Collection写成Stream字节流方式存储到文件中 WriteDatabaseToStream编码以下:
- public void WriteDatabaseToStream(Stream stream)
- {
- string serilizedInfo = string.Empty;
- serilizedInfo = _databaseName;
- //获取数据库中表数据
- foreach (var item in _tables)
- {
- serilizedInfo = string.Concat(
- serilizedInfo,
- Environment.NewLine,
- CreateFormattedTableType(item.RowType));
- }
- if (!string.IsNullOrEmpty(_password))
- {
- //若是有采用了加密方式 则把数据进行加密 返回加密的字符串 .在存储到文件中
- serilizedInfo = Cryptography.Encrypt(serilizedInfo, _password);
- }
- using (StreamWriter writer = new StreamWriter(stream))
- {
- //把数据字符串写入字节流中 方式写到独立存储空间硬盘文件上
- writer.Write(serilizedInfo);
- writer.Flush();
- writer.Close();
- }
- }
获取字节流格式后, 获取数据库对应每一个表, 利用string.Concat方法拼接字符串, 若是在建立表时设置须要加密则功过加密方法返回加密后字符串, 最后把字符串写入存储流中 进行保存独立存储硬盘空间上 实现了数据的存储.
如上实现了Windows Phone DB 从建立数据库-建立数据表结构-插入数据-保存数据到独立存储空间上,整个流程. 固然更多操做请下载源码参考.
到了这儿我在回到这个小节的主题,Windows Phone DB 给咱们带来了什么?
Windows Phone DB给咱们带来利用独立存储方式如今WP7对本地数据访问支持最完整解决方案.它把Silverlight的独立存储机制运用在数据库存储上最大化了. 它利用Silverlight类库模拟了一个小型的数据库存储系统[虽然不少东西不支持]. 你能够看出数据库和表结构 彻底可T-Sql没有任何关联, 利用类于类之间关系进行约束的.
不少人又不由要问. 这样的形式是不完整的. 我要它支持View. 存储过程Proc. Transaction事务操做等. 那么剩下工做就是采用类于类之间关联进行约束建立, 它开辟了在WP7利用独立存储方式模拟数据库存储功能一种独特视角[虽然不是最好方式] 开阔咱们解决问题更广的视野. 这一点是我我的为Windows Phone DB 作的最成功的地方. 但从这点于Effproz和SQlite来讲 WPDB是具备创造性的思惟的.
固然若是你认为它不能知足你的工做, 太过简单, 对于一个难度不大 但视角独特 并且开源项目来讲, 你彻底能够在这个基础之上加上更多的功能 模拟出更好数据库支持. 若是你好的建议 或疑问请在留言中提出.
<3>Windows Phone DB小节
固然短短一篇文章也许没法更加详细阐述WPDB所具备的各类特色. 我也是做为一个初学者利用短短一种时间对源码进行摸索. 虽然WPDB性能和实用性不及Effproz和SQlite 但做者的创造性思惟的方式 给个人映像深入.
由此WPDB和T-SQl没有任何关联. 因此就没有QueryTool查询工具可言了.另外对于Silverlight异步通讯而言, 本次源码中并无实现对类实例化进行远程传输JSon格式的实现, 其实这个功能彻底能够再WPDB基础之上模拟出来.
至于说性能和其余功能完善. WPDB和其余数据库没有任何可比性. 那是由于没有共同的基础条件. 可是WPDB在创造性能够说独树一帜的. 以上均为我我的详细分析源码后得到一点感觉.若是你有更好意见和建议能够再留言中提出.