WP7 - Local Database概論 - 2

Windows Phone 7 – Local Database概論 - 2

在<Windows Phone 7 - Local Database概論 - 1>介紹了有關Local Database的觀念之後,接下來這篇主要說明

如何來操作建立好的Data Context物件。由於在操作Data Context還是以物件導向的觀念,配合Lambda語法

撰寫LINQ陳述句,所以對於LINQ不太熟的話,可以參考<101 LINQ Samples>。

 

〉操作Data Context

(a) INSERT

   1: private void btnInsert_Click(object sender, RoutedEventArgs e)
   2: {
   3:     //取得Local Database連線後的DataContext物件
   4:     DBHandler tDBHandler = new DBHandler(DBHandler.DBConnection);
   5:     //產生二個Contacts
   6:     Contacts tNewContact1 = new Contacts();
   7:     tNewContact1.Name = "Pou";
   8:     tNewContact1.PhoneNumber = "0932xxxxxx";
   9:  
  10:     Contacts tNewContact2 = new Contacts();
  11:     tNewContact2.Name = "John";
  12:     tNewContact2.PhoneNumber = "0912xxxxxx";
  13:     //將Contacts變成一個IEnumerable<T>
  14:     List<Contacts> tAllConact = new List<Contacts>();
  15:     tAllConact.Add(tNewContact1);
  16:     tAllConact.Add(tNewContact2);
  17:  
  18:     //新增資料至Local Database
  19:     tDBHandler.Contacts.InsertAllOnSubmit(tAllConact);
  20:     //發出更新資訊
  21:     tDBHandler.SubmitChanges();
  22: }

操作LINQ to SQL針對資料的建立,需使用物件操作概念,將要加入的資料先行實例為物件,將欄位資料當作屬性來控制,

最後在依賴LINQ to SQL提供的方法:InsertAllOnSubmit或InsertOnSubmit選擇是多筆或單筆的增加資料。更詳細的內容,

可以參考:<How to: Insert Rows Into the Database (LINQ to SQL)>。

 

(b) SELECT

在WP7要操作Local Database需使用LINQ,透過LINQ串聯實體資料與物件之間的操作關係。在LINQ to SQL的運作與LINQ技術有些不同,

LINQ to SQL是採用物件對應的方式,來控制實際的資料,因此,LINQ to SQL是在runtime的過程裡,轉換成實際的T-SQL指定來執行的

這與LINQ最大不同於:傳統的LINQ被執行於Application Layer的Memory,而LINQ to SQL是直接對Local Database操作。

以下簡單舉個查詢上述新增的二個Contacts:

   1: private void btnSelect_Click(object sender, RoutedEventArgs e)
   2: {
   3:     DBHandler tDBHandler = new DBHandler(DBHandler.DBConnection);
   4:     //取得所有Contacts
   5:     var tContacts = from Contacts in tDBHandler.Contacts
   6:                     select Contacts;
   7:     //執行LINQ to SQL語法,將實際資料轉至Collection物件
   8:     List<Contacts> tAllContacts = new ObservableCollection<Contacts>(tContacts).ToList();
   9:  
  10:     String tContactsMsg = string.Empty;
  11:     foreach (Contacts tItem in tAllContacts)
  12:     {
  13:         tContactsMsg += string.Format("ID:{0}, Name:{1}, Phone:{2}\r\n", 
  14:                 tItem.ID, tItem.Name, tItem.PhoneNumber);
  15:     }
  16:     MessageBox.Show(tContactsMsg);
  17: }

上述程式一段ObservableCollection<T>,並將寫好的LINQ指令放入它的實例化參數中,為什麼需要這樣?

由於LINQ To SQL不像傳統的LINQ直接寫就會執行,它需要透過ObservableCollection<T>時,才會將LINQ指令

放入至集合類別中進行執行,這跟以前查詢的作法是不太一樣的,要特別注意。

 

(c) UPDATE

針對資料的Update主要有三個步驟:(1) 查詢出要修改的項目;(2) 修改內容;(3) Sumit修改後的結果至資料庫中。

以下舉個修改電話的例子:

   1: private void btnUpdate_Click(object sender, RoutedEventArgs e)
   2: {
   3:     DBHandler tDBHandler = new DBHandler(DBHandler.DBConnection);
   4:     //搜尋指定的對象
   5:     var tContacts = from Contacts in tDBHandler.Contacts
   6:                     where Contacts.Name == "Pou"
   7:                     select Contacts;
   8:     //執行LINQ to SQL語法,將實際資料轉至Collection物件
   9:     Contacts tSpecContact = new ObservableCollection<Contacts>(tContacts).Single();
  10:     //修改電話
  11:     tSpecContact.PhoneNumber = "0983444111";
  12:     //記得一定要SUBMIT
  13:     tDBHandler.SubmitChanges();
  14: }

詳細關於操作Update的作法,可以參考<How to: Update Rows in the Database (LINQ to SQL)>。

另外,如果實作時把資料物件(data object)與Page上的Control做Binding的話,要記得做SubmitChange()方法喔,

呼叫該方法的地方,可以是在:OnNavigatedFrom()或OnNavigatedTo()的時候,以免資料漏掉。

 

(d) DELETE

刪除資料一樣有幾步驟要注意:(1) 搜尋要刪除的資料範圍;(2) 使用DeleteOnSubmit()或DeleteAllOnSubmit()刪除資料;

(3) Submit刪除的資料至資料庫之中。舉個簡單的例子:

   1: private void btnDelete_Click(object sender, RoutedEventArgs e)
   2: {
   3:     DBHandler tDBHandler = new DBHandler(DBHandler.DBConnection);
   4:     var tContacts = from Contacts in tDBHandler.Contacts
   5:                     where Contacts.Name == "John"
   6:                     select Contacts;
   7:     //執行LINQ to SQL語法,將實際資料轉至Collection物件
   8:     Contacts tSpecContact = new ObservableCollection<Contacts>(tContacts).Single();
   9:     //刪除指定的資料
  10:     tDBHandler.Contacts.DeleteOnSubmit(tSpecContact);
  11:  
  12:     tDBHandler.SubmitChanges();
  13: }

詳細關於操作Delete的作法,可以參考<How to: Delete Rows From the Database (LINQ to SQL)>。

 

〉修改Local Database版本與DB Schema

由於當使用CreateDatabase()方法時,Database預設的版本號為:0。因此,要針對Database的版本號進行擷取或修改時,

需要透過「DatabaseSchemaUpdater」類別來操作。以下將簡介如何使用DatabaseSchemaUpdater類別:

   1: using Microsoft.Phone.Data.Linq;
   2:  
   3: public void UpgradeSchema()
   4: {
   5:     DBHandler tDBHandler = new DBHandler(DBHandler.DBConnection);
   6:     //取得DatabaseSchemaUpdate物件,由DataContext產生而來
   7:     DatabaseSchemaUpdater gUpdater = tDBHandler.CreateDatabaseSchemaUpdater();
   8:     if (gUpdater.DatabaseSchemaVersion == 0)
   9:     {
  10:         //針對Contacts資料表增加資料欄位
  11:         gUpdater.AddColumn<Contacts>("Parent");
  12:         gUpdater.AddColumn<Contacts>("Address");
  13:         //修改版本號
  14:         gUpdater.DatabaseSchemaVersion = 1;
  15:         //執行
  16:         gUpdater.Execute();
  17:     }
  18: }

在DatabaseSchemaUpdater類別裡,還有其他重要的方法,包括:

AddIndex<T>:增加索引,T代表新的索引類別;

AddAssociation<T>:增加關聯,T代表定義的新關聯類別;

AddTable<T>:增加新的資料表,T代表新的資料表類別;

 

〉針對Local Database加密

為何會使用Local Database,通常在商業軟件裡需要把一些希望在沒有網路連接仍可以操作的資料,或是一些基本的資料

讓用戶不需要保持與Server溝通的狀況下就能使用,甚至還有包括一些用戶針對這App的機密資訊,對於這些東西,可能

過去簡單一點會使用文字檔(*.txt)、設定檔(*.ini)或SQLite都是為了保存這些資料內容。

但至於保存下來,就有可能被有心人事透過手機連接到電腦時,把SD Card裡的資訊也取出來,所以「加密」就很重要了

因此,LINQ to SQL在WP7上針對Local Database的Connection String增加了一些加密與參數的設定

以下將介紹可用的參數:

參數 描述
data source(或datasource) 指定資料庫名稱與路徑。使用該connection string需要去instance一個Data context object才可以使用。
Password(或Pwd、database password、ssce:database password) 設定資料庫密碼。長度40字元。加密機制預設是沒有的,如果需要則加上此關鍵字。另外,當建立好的資料庫,是無法在加密的
max buffer size 或(ssce:max buffer size) 指定最大的記憶體存量。以kilobyte為單位,預設:384,最大值5120
max database size(或ssce:max database size) 指定Local Database的最大size,以megabytes為單位。預設值為:32,最大值:512
mode(或file mode、ssce:mode) 設定開啟資料庫的模式:
‧Read Write:預設模式,允許讀、寫並行的功能。
‧Read Only:允許只能讀取copy的資料庫。
‧Exclusive:不允許Processes打開或存取資料庫。
‧Shared Read:
Culture Identifier 設定資料庫的語系代碼。詳細參考<Culture and Language Support for Windows Phone>,這會影響資料的排序與搜尋。
Case Sensitive(或CaseSensitive) 預設值為false。以bool值為識別,true代表需要識別大小寫進行排序規格的調整;false代表不用。

簡單舉個例子:「建立一個支援固定密碼的資料庫」:

   1: public class DBHandler : DataContext
   2: {
   3:     //設定支援密碼與大小寫排序的資料庫
   4:     public static string DBConnection = 
   5:         "Data Source=isostore:/students.sdf;Case Sensitive=true;Passwork=test";
   6:  
   7:     public DBHandler(string pDBConnection) : base(pDBConnection) { }
   8:  
   9:     public Table<Contacts> gContacts;
  10: }

 

[補充]

在操作資料過程中,如果有發現在DataContext定義Table時,在Table Columns的資料型別有不太清楚的部分,可以先參考

<System.Data.Linq.Mapping Namespace>、<Table<TEntity> 類別>、<HOW TO:將資料表表示為類別 (LINQ to SQL)>這幾

篇所提供的類別範例與方法清單,這些我覺得對於實作Local Database在定義上非常有幫助。

 

[程式範例]

======

以上是分享有關如何操作DataContext與Upgrade你的Databae,其中我覺得在開發Mobile App要特別注意的,

在於「加密」,由於DB是安裝在手機裡,如果用戶透過特殊手段就可以把資料從SD卡中取得,這要特別小心。

另外,在操作WP7上的Local Database其實有些東西跟SQL CE的使用很相近,所以我覺得最需要補充的只在「

LINQ to SQL」。希望對大家有所幫助。

 

References:

Local Database Overview for Windows Phone

DatabaseSchemaUpdater Class (調整database在table或schema的部分,必讀)

Culture and Language Support for Windows Phone

Local Database Connection Strings for Windows Phone

How to: Create a Basic Local Database Application for Windows Phone

Introduction to LINQ Queries (C#) (學習LINQ時,基本觀念的建立)

Local Database Support for Windows Phone 7 (第三方支援WP7的local database)

[WP7.1] Local Database (SQL Server CE) Performance

A simple IsolatedStorage database for WP7, but I don't know how to data binding with Listbox.

LINQ to SQL 物件模型 (必讀) & TableAttribute 類別