<1>初识Windows Phone DB
WPDB是利用Silverlight的独立存储[IsolatedStorage]机制为WP7访问数据库加以支持. 目前的版本只是针对开发人员. 使用简单. 开源. 其实它内部存储数据的实质就是利用IsolatedStorage. Silverlight的IsolatedStorage是一种类似Cookie的静态存储机制.可以将一些基本类型(String,Int)的信息甚至是自定义类型序列化后的静态存储于客户端文件中.
独立存储[IsolatedStorage]是一个局部信任机制. 什么叫局部? 当你创建一个Silverlight应用程序时会在硬盘上创建相应独立的存储区域. 这里面独立是相对于不同Silverlight Project而言的. 当然如果应用程序中存在多个程序集[Project],那么存储空间在这多个程序集之间是共享的.
<a target="_blank" href="http://blog.51cto.com/attachment/201201/121253668.jpg"></a>
<2>Windows Phone DB给我们带来什么?
先不着急回答这个问题.WPDB是开源的 你在可以在CodePlex上下载它相关源码:
下载完源码用VS工具打开.预览整个Solutions:
<a target="_blank" href="http://blog.51cto.com/attachment/201201/121259431.jpg"></a>
Solutions中包含两个项目: 第一个为WPDB的源码项目 下面是对WPDB测试项目. 二者关系是测试项目对源码项目采取了引用. 先不管那么多运行起来看看效果:
<a target="_blank" href="http://blog.51cto.com/attachment/201201/121304206.jpg"></a>
页面只有一个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源码结构 分析如下:
<a target="_blank" href="http://blog.51cto.com/attachment/201201/121310902.jpg"></a>
如上分析可见.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在创造性可以说独树一帜的. 以上均为我个人详细分析源码后获得一点感受.如果你有更好意见和建议可以再留言中提出.
本文转自chenkaiunion 51CTO博客,原文链接:http://blog.51cto.com/chenkai/764668