在上一篇多樣化實現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在創造性能夠說獨樹一幟的. 以上均爲我我的詳細分析源碼後得到一點感覺.若是你有更好意見和建議能夠再留言中提出.