<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