天天看點

多樣化實作Windows Phone 7本地資料庫通路<2>

<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>

&lt;2&gt;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&lt;ITable&gt;(new List&lt;ITable&gt;());   

        _loadedTables = new Dictionary&lt;Type, bool&gt;();    

構造函數中封裝DAtabase基本屬性,  其中有必要說一下ReadOnlyCollection&lt;ITable&gt; 它其實目的是在Database對象建立一個Collection集合來存儲表結構.  裡面表結構實作是父類接口ITable.有了DataBase我們建立一個Persion表:

//建立庫 [調用代碼]    

Database.DeleteDatabase("test");    

Database db = Database.CreateDatabase("test");     

//建立相應表     

db.CreateTable&lt;Person&gt;();    

建立表CreateTable方法定義:

public void CreateTable&lt;T&gt;()     

    {     

     //判斷表是否存在    

  if (DoesTableExists(typeof(T)))    

         throw new DatabaseExistsException(string.Format(DatabaseResources.TableExistsExceptionText, typeof(T).FullName));    

      }    

     else    

     {   

           //奧 盡然這種寫法 已經利用定義Collection定義好List大小Size 難道也直接考慮到List性能    

            List&lt;ITable&gt; tables = new List&lt;ITable&gt;(_tables);     

          //建立表 其實就是New 一個Table執行個體 指定Table的名稱和通路密碼    

            tables.Add(SilverlightPhoneDatabase.Table&lt;T&gt;.CreateTable(_databaseName, _password));    

         //建立成功後 把這個建立的表添加指定的資料庫中    

       _tables = new ReadOnlyCollection&lt;ITable&gt;(tables);    

        }    

      } 

建立表同時也與表執行個體類型關聯. 這是我們需要定義一個Persion實體類[源碼附有下載下傳].  把建立的TAble表添加到Database表存儲集合中, 實作與資料庫的關聯.  有了表和資料庫 快速插入10條記錄: 資料插入操作:

private void SaveTest()    

{    

//建立庫和表     

     Database.DeleteDatabase("test");    

         Database db = Database.CreateDatabase("test");   

         db.CreateTable&lt;Person&gt;();    

     //資料庫表存在情況下     

     if (db.Table&lt;Person&gt;() != null)    

     {    

           for (int i = 0; i &lt; 10; i++)    

               {   

             //添加資料  NewRandomPerson傳回一個随機的實體類Persion    

               db.Table&lt;Person&gt;().Add(NewRandomPerson());   

             }    

         //儲存資料    

         db.Save();    

          this.SaveDBLabel.Foreground = new SolidColorBrush(Colors.Green);    

         }    

          else   

        {    

       this.SaveDBLabel.Foreground = new SolidColorBrush(Colors.Red);   

     }    

資料添加到DAtaBase對象下屬性ReadOnlyCollection&lt;ITable&gt; 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是具有創造性的思維的.

當然如果你認為它不能滿足你的工作, 太過簡單, 對于一個難度不大 但視角獨特 而且開源項目來說, 你完全可以在這個基礎之上加上更多的功能 模拟出更好資料庫支援. 如果你好的建議 或疑問請在留言中提出.

&lt;3&gt;Windows Phone DB小節

當然短短一篇文章也許無法更加詳細闡述WPDB所具有的各種特點. 我也是作為一個初學者利用短短一種時間對源碼進行摸索. 雖然WPDB性能和實用性不及Effproz和SQlite 但作者的創造性思維的方式 給我的映像深刻.

由此WPDB和T-SQl沒有任何關聯. 是以就沒有QueryTool查詢工具可言了.另外對于Silverlight異步通信而言, 本次源碼中并沒有實作對類執行個體化進行遠端傳輸JSon格式的實作, 其實這個功能完全可以再WPDB基礎之上模拟出來.

至于說性能和其他功能完善. WPDB和其他資料庫沒有任何可比性. 那是因為沒有共同的基礎條件. 但是WPDB在創造性可以說獨樹一幟的. 以上均為我個人詳細分析源碼後獲得一點感受.如果你有更好意見和建議可以再留言中提出.

本文轉自chenkaiunion 51CTO部落格,原文連結:http://blog.51cto.com/chenkai/764668