多樣化實現Windows Phone 7本地數據庫訪問<下>

作者: chenkai  來源: 博客園  發布時間: 2010-09-06 16:07  閱讀: 2548 次  推薦: 0   原文鏈接   [收藏]  

  在上一篇多樣化實現Windows Phone 7本地數據庫訪問<上>采用兩種方式Effproze和SQlite來驗證Window Phone 7訪問本地數據庫.驗證結論是可行的.  得到圓友及時反饋當然也發現一些細節上問題. 例如Effproze利用文件/內存模式 找不到指定的硬盤上數據庫文件. Sqlite中支持Windows Phone 7 API沒有相關文檔. 以及SQlite創建后類似Effproze找不到指定存儲文件等?類似這些問題 正在尋找和驗證相關解決方案 稍后我會專門整理出一篇文章來詳細說明. 本篇將繼續驗證Windows Phone 7訪問本地數據庫其他方式-Windows  Phone DB

  <1>初識Windows Phone DB

  其實看到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)的信息甚至是自定義類型序列化后的靜態存儲于客戶端文件中.

  獨立存儲[IsolatedStorage]是一個局部信任機制. 什么叫局部? 當你創建一個Silverlight應用程序時會在硬盤上創建相應獨立的存儲區域.  這里面獨立是相對于不同Silverlight Project而言的. 當然如果應用程序中存在多個程序集[Project],那么存儲空間在這多個程序集之間是共享的.

  Silverlight限制了客戶端Silverlight應用程序不能訪問全部的文件系統,只能通過獨立存儲機制提供虛擬文件系統,訪問數據流對象. 這樣一來類似我們Application 有了自己一塊硬盤空間一樣.獨立存儲空間內就可以放置任意類型的文件. XML /.txt等. 4版本中空間大小也是可以控制的. 更多資源請參考.Introduce IsolatedStorage MSDN  由此也能看出Silverlight也涵蓋WP7日常開發 當然還有Silverlight能做還不止這些 如下圖:Silverlight 涵蓋圖。

  <2>Windows Phone DB給我們帶來什么?

  先不著急回答這個問題.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在創造性可以說獨樹一幟的. 以上均為我個人詳細分析源碼后獲得一點感受.如果你有更好意見和建議可以再留言中提出.

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()