無論您是已經(jīng)決定將應(yīng)用程序和數(shù)據(jù)從以前的 Pocket PC 工具(Microsoft eMbedded Visual Basic 和 Pocket Access)遷移到目前的技術(shù)(Microsoft .NET Compact Framework 和 Microsoft SQL Server CE),還是正在考慮這一決定,您都需要研究這一遷移的一些困難的理由。
第一個理由是您的設(shè)備將提高性能。在設(shè)備處理器(即使是最新的最優(yōu)秀的處理器)上,性能無疑非常重要。在 SQL Server CE 中正確地設(shè)置數(shù)據(jù)庫(通過適當?shù)拿荑€、索引等)以后,它的性能將完全超過 Pocket Access — 有時可以超過好多倍。
第二個理由是 SQL Server CE 中更為豐富的類型系統(tǒng)將使您的設(shè)備能夠更有效地存儲數(shù)據(jù)。您可以存儲在 Pocket Access 中的所有內(nèi)容都可以存儲在 SQL Server CE 中(不止如此)。因為該類型系統(tǒng)是 SQL Server 2000 的類型系統(tǒng)的干凈子集,所以同步也會更加容易。
第三個理由是當前的數(shù)據(jù)訪問中間件 (ADO.NET) 將為您提供更多的功能,以使您除了操作數(shù)據(jù)的定義以外,還可以讀取和操作數(shù)據(jù)本身。新增的且本來斷開的模型(由 DataSet 表明)使您在數(shù)據(jù)的使用方式方面具有更多的自由。可以將 DataSet 發(fā)送到 XML Web 服務(wù)(當您通過 ASP.NET 創(chuàng)建 XML Web 服務(wù)時,DataSet 類型將受到天然支持)。您可以將 DataSet 作為 XML(包含 XML 架構(gòu)信息,或者在單獨的文件中)存儲到文件系統(tǒng)中(可以將 XML 從相同的文件重新讀取到 DataSet 中)。
最后一個理由是,除了數(shù)據(jù)操作以外,更加豐富的 SQL 語法還使您在讀取數(shù)據(jù)時具有更多的選擇(使用子查詢、外部聯(lián)接等)。以前,您需要在檢索 Recordset 之后的代碼中實現(xiàn)大量邏輯,而現(xiàn)在您可以直接在它所屬的 SQL 命令中完成該工作。在以前的代碼中,完成諸如通過 LTRIM 或 CASE...WHEN...THEN...ELSE...END 語句格式化 SELECT 語句中的列的工作要困難得多,并且通常會更慢。
當從以前的 Pocket PC 應(yīng)用程序進行的遷移同時涉及到數(shù)據(jù)和代碼的遷移時,您可以在下列三個不同的級別執(zhí)行遷移:
• |
數(shù)據(jù)庫 |
• |
數(shù)據(jù)庫中間件 |
• |
源代碼 |
在數(shù)據(jù)庫級別,可以將數(shù)據(jù)和代碼從 Pocket Access 遷移到 SQL Server CE。主要差異與受支持的數(shù)據(jù)類型有關(guān)。當您遷移數(shù)據(jù)訪問代碼時,數(shù)據(jù)庫中間件中的差異主要與受支持的對象以及使用這些對象的語法有關(guān)。通常,當您遷移源代碼時,差異同時與不同的語言以及受支持的類庫有關(guān)。下列各部分將描述不同級別之間的差異。
從 Pocket Access 遷移到 SQL Server CE
通常,以前的 Pocket PC 應(yīng)用程序中的數(shù)據(jù)源自桌面計算機的 Microsoft Access 數(shù)據(jù)庫。當需要進行桌面計算機復制時,通常會借助于 Microsoft ActiveSync 中內(nèi)置的同步功能在桌面計算機和設(shè)備之間復制這些數(shù)據(jù)。當數(shù)據(jù)遷移到 SQL Server CE 時,第一步是將現(xiàn)有的 Access 數(shù)據(jù)庫遷移到 SQL Server 2000。
您可以從 Access 內(nèi)部執(zhí)行該遷移,方法是通過連接到 SQL Server 2000 數(shù)據(jù)庫的開放式數(shù)據(jù)庫連接 (ODBC) 數(shù)據(jù)源來導出表。然后,您可以通過使用遠程數(shù)據(jù)訪問 (RDA) 將 SQL Server 2000 中的數(shù)據(jù)復制到設(shè)備上的 SQL Server CE。有關(guān)如何完成該復制的詳細信息,請參閱本文中的“同步”一節(jié)。
表 1 顯示了每個數(shù)據(jù)庫支持的不同數(shù)據(jù)類型的映射。
表 1. 數(shù)據(jù)類型映射 | |||
Access 數(shù)據(jù)類型 | Pocket Access 類型 | SQL Server 2000 類型 | SQL Server CE 類型 |
Text |
varchar |
nvarchar |
nvarchar |
Memo |
text |
ntext |
ntext |
LongInt |
integer |
int |
int |
Int, Byte |
smallint |
smallint |
smallint |
Double, Single |
double |
float |
float |
Replication ID |
varbinary |
uniqueidentifier |
uniqueidentifier |
Date/Time |
datetime |
datetime |
datetime |
Currency |
double |
money |
money |
AutoNumber |
integer |
int |
int |
YesNo |
boolean |
bit |
bit |
OleObject |
varbinary |
image |
image |
HyperLink |
text |
ntext |
ntext |
Lookup |
varchar |
nvarchar |
nvarchar |
SQL Server 2000 支持所有 Access 數(shù)據(jù)類型,并且因為 SQL Server CE 支持(不用轉(zhuǎn)換)導出中生成的所有類型,所以遷移過程中不會丟失任何信息。
從 ADO CE 遷移到 ADO.NET
ActiveX Data Objects for Windows CE (ADO CE) 是作為 ADO 的設(shè)備版本創(chuàng)建的,并且第一個版本 (3.0) 只支持 Pocket Access。在創(chuàng)建 SQL Server CE 時,更新了 ADO CE 以支持它。盡管很多以前的 Pocket PC 應(yīng)用程序使用 ADO CE(3.0) 的第一個版本來訪問 Pocket Access 數(shù)據(jù)庫,但本節(jié)中的信息只與最新版本 (3.1) 有關(guān)。不過,下列代碼示例也應(yīng)該適用于 ADO CE .0。
ADO CE 支持下列對象:Recordset、Field(和集合)、Connection 和 Error(和集合)。但是,ADO CE 不支持完整(桌面)ADO 實現(xiàn)中包含的 Command 對象。作為 ADO CE 的擴展,ADO XCE 包含管理數(shù)據(jù)庫的功能,如操作表、字段和其他數(shù)據(jù)庫對象。
.NET Compact Framework 中的 ADO.NET 是完整 .NET Framework 數(shù)據(jù)訪問中間件的設(shè)備版本。您可以在“System.Data.SqlServerCe”命名空間中找到 ADO.NET for SQL Server CE,它通常被稱為 SQL Server CE 的托管提供程序。該托管提供程序中最重要的對象是:SqlCeConnection(用于連接到數(shù)據(jù)庫)、SqlCeDataAdapter(用于訪問數(shù)據(jù)庫中的數(shù)據(jù))、SqlCeCommandBuilder(用于生成 SQL 命令以便在數(shù)據(jù)庫中保存數(shù)據(jù))、SqlCeCommand(用于向數(shù)據(jù)庫發(fā)出 SQL 命令)、SqlCeDataReader(用于從數(shù)據(jù)庫中快速地順序讀取數(shù)據(jù))、SqlCeEngine(用于管理數(shù)據(jù)庫)以及 SqlCeException(用于錯誤處理)。有關(guān) ADO CE 和 ADO.NET 的詳細信息,請參閱 Microsoft Visual Studio .NET 幫助文件。
在 ADO CE 中執(zhí)行的多個重要操作可以通過 ADO.NET 來完成。首先,您需要打開數(shù)據(jù)庫連接。在 ADO CE 中,您可以按如下方式打開數(shù)據(jù)庫。
Dim connection AS ADOCE.Connection Set connection = CreateObject("ADOCE.Connection.3.1") connection.ConnectionString = "Data Source=\MyDatabase.cdb" connection.Open
您還可以將連接字符串作為連接的 Open 方法的參數(shù)提供。調(diào)用 Connection 對象上的 Close 方法可以關(guān)閉該連接。
如果您要使用 ADO.NET 和 Visual Basic .NET,則您可以按如下方式打開數(shù)據(jù)庫連接。
Dim connection As SqlCeConnection connection = New SqlCeConnection("Data Source=\MyDatabase.sdf") connection.Open()
與 ADO CE 類似,該連接的 Close 方法可以關(guān)閉該連接。
在 C# 中,相同的代碼如下所示。
SqlCeConnectionconnection connection = new SqlCeConnection(@"Data Source=\MyDatabase.sdf"); connection.Open();
因為越早考慮錯誤處理越好,所以您可以查看 ADO CE 中是如何處理錯誤的。首先,您需要按如下方式設(shè)置錯誤處理程序:
On Error Resume Next Err.Clear
在應(yīng)用程序執(zhí)行每個數(shù)據(jù)庫命令之后,Connection 對象上的錯誤集合 (Errors) 包含已經(jīng)發(fā)生的任何錯誤。您可以通過使用以下代碼讓應(yīng)用程序報告任何錯誤。
If (Err.Number <> 0) Then For i = 1 To connection.Errors.Count MsgBox connection.Errors(i).Number & " - " & _ connection.Errors(i).Description, vbCritical, "Error" Next i Err.Clear End If
對于每個錯誤,都會顯示一個消息框,其中帶有錯誤號和錯誤說明。當您使用 Pocket Access 數(shù)據(jù)庫時,ADO CE 中的錯誤對象還支持本機錯誤 (NativeError) 和錯誤源 (Source) 的屬性。
在 Visual Basic .NET 中,您可以通過使用 Try Catch 結(jié)構(gòu)處理錯誤。下面是用于捕獲和報告 ADO.NET 錯誤的 Visual Basic .NET 代碼。
Try ' Database code Catch ex As SqlCeException If Not ex.InnerException Is Nothing Then MessageBox.Show("Inner Exception: " + ex.InnerException.ToString()) End If Dim s As StringBuilder = New StringBuilder() Dim error As SqlCeError For Each error In ex.Errors s.Append("Error Code: " + error.HResult.ToString("X")) s.Append(vbCrLf + "Message : " + error.Message) s.Append(vbCrLf + "Minor Err.: " + error.NativeError) s.Append(vbCrLf + "Source : " + error.Source) Dim numericErrorParameter As Integer For Each numericErrorParameter In error.NumericErrorParameters If numericErrorParameter <> 0 Then s.Append(vbCrLf + "Num. Par. : " + numericErrorParameter) End If Next Dim errorParameter As String For Each errorParameter In error.ErrorParameters If errorParameter.Length > 0 Then s.Append(vbCrLf + "Err. Par. : " + errorParameter) End If Next MessageBox.Show(s.ToString()) s.Remove(0, s.Length) Next End Try
在 ADO.NET 中,發(fā)生的異常(錯誤)包含的信息要比 ADO CE 提供的信息多得多。該信息幫助開發(fā)人員更快地查找程序錯誤,并且還在處理每個異常方面提供了更多的控制。首先,應(yīng)用程序在消息框中報告任何內(nèi)部異常,然后,應(yīng)用程序在每個錯誤的消息框中報告(通過詳細信息)異常對象 (ex) 上的集合 (Errors) 中的所有錯誤。
在 C# 中,代碼如下所示。 try { // Database code } catch (SqlCeExceptionex) { if(ex.InnerException != null) MessageBox.Show("Inner Exception: " + ex.InnerException.ToString()); StringBuilder s = new StringBuilder(); foreach (SqlCeError error in ex.Errors) { s.Append("Error Code: " + error.HResult.ToString("X")); s.Append("\nMessage : " + error.Message); s.Append("\nMinor Err.: " + error.NativeError); s.Append("\nSource : " + error.Source); foreach (int numericErrorParameter in error.NumericErrorParameters) if(numericErrorParameter != 0) s.Append("\nNum. Par. : " + numericErrorParameter); foreach (string errorParameter in error.ErrorParameters) if(errorParameter.Length > 0) s.Append("\nErr. Par. : " + errorParameter); MessageBox.Show(s.ToString()); s.Remove(0, s.Length); } }
既然您具有連接并且可以處理返回的錯誤,那么您就可以開始與數(shù)據(jù)庫交互了。最重要的操作是在數(shù)據(jù)庫中查詢數(shù)據(jù)。在 ADO CE 中,可以用下列兩種方式查詢數(shù)據(jù)庫:通過使用 Recordset 對象上的 Open 方法,或者通過使用 Connection 對象上的 Execute 方法。
使用 Recordset 對象的代碼如下所示。
Dim rs As ADOCE.Recordset Dim sql As String sql = "SELECT* FROM Customers" Set rs = CreateObject("ADOCE.Recordset.3.1") rs.Open sql, connection, adOpenDynamic, adLockOptimistic
如果您從前使用 Connection 對象,則您可以用以下行替換最后兩行。
Set rs = connection.Execute(sql)
使用數(shù)據(jù)適配器的相應(yīng) Visual Basic .NET 代碼如下所示。
Dim sql As String = "SELECT* FROM Customers" Dim da As New SqlCeDataAdapter(sql, connection) Dim ds As New DataSet da.Fill(ds, "Customers")
在前面的代碼中,通過將數(shù)據(jù)庫 (SQL) 命令和 Connection 對象作為構(gòu)造函數(shù)的參數(shù)進行傳遞,創(chuàng)建了一個新的數(shù)據(jù)適配器對象 (da)。然后,通過使用該數(shù)據(jù)適配器上的 Fill 方法為 DataSet (ds) 填充了數(shù)據(jù)。Fill 方法的第二個參數(shù)設(shè)置了 DataSet 中剛剛檢索的表的名稱。在后臺,數(shù)據(jù)適配器使用 SqlCeCommand 對象(在它的 SelectCommand 屬性中)查詢數(shù)據(jù)庫。
在 C# 中,代碼如下所示。
string sql = "SELECT* FROM Customers"; SqlCeDataAdapterda = new SqlCeDataAdapter(sql, connection); DataSetds = new DataSet; da.Fill(ds, "Customers");
ADO.NET 中提供的另一種讀取數(shù)據(jù)的方式是 SqlCeDataReader。您可以使用它以一種非常高效的方式來順序讀取數(shù)據(jù)。當性能很重要以及數(shù)據(jù)量很高時,您應(yīng)該考慮該選項。以下代碼顯示了一個有關(guān)如何使用 SqlCeDataReader 的示例。
Dim sql As String = "SELECT* FROM Customers" Dim cmd As New SqlCeCommand(sql, connection) Dim dr As SqlCeDataReader= cmd.ExecuteReader() While dr.Read ListBox1.Items.Add(dr(1)) End While
當從命令對象創(chuàng)建讀取器時,使用第二個列 (dr(1)) 向列表框 (ListBox1) 中添加行。
在 C# 中,代碼如下所示。
string sql = "SELECT* FROM Customers"; SqlCeCommandcmd = new SqlCeCommand(sql, connection); SqlCeDataReaderdr = cmd.ExecuteReader();
在 ADO CE 中,唯一受支持的執(zhí)行不返回任何數(shù)據(jù)的命令的方式是使用 Connection 對象上的 Execute 方法,然后通過使用以下代碼忽略返回值。
connection.Execute("DELETE Customers WHERE CustomerID=1")
在 Visual Basic .NET 中,您可以使用 SqlCeCommand 對象執(zhí)行命令,如下所示。
Dim cmd As SqlCeCommand= connection.CreateCommand() cmd.CommandText = "DELETE Customers WHERE CustomerID=1" cmd.ExecuteNonQuery()
在 C# 中,代碼如下所示。
SqlCeCommandcmd = connection.CreateCommand(); cmd.CommandText = "DELETE Customers WHERE CustomerID=1"; cmd.ExecuteNonQuery();
您還可以通過向構(gòu)造函數(shù)提供命令文本和連接來創(chuàng)建命令對象。
該命令對象具有 ExecuteScalar 方法,當您只需要返回單個值時,可以使用該方法。如果該命令只返回一個帶有一個列的行,則您可以使用以下代碼。
Dim cmd As SqlCeCommand= connection.CreateCommand() cmd.CommandText = "SELECTCOUNT(*) FROM Customers" Dim numberOfCustomers As Integer = cmd.ExecuteScalar()
在 C# 中,代碼如下所示。
SqlCeCommandcmd = connection.CreateCommand(); cmd.CommandText = "SELECTCOUNT(*) FROM Customers"; int numberOfCustomers = (int)cmd.ExecuteScalar();
該命令對象還支持參數(shù)(但是,它不支持命名參數(shù)),您可能發(fā)現(xiàn)這在多次使用命令時非常有用,因為參數(shù)化查詢避免了重復計算查詢計劃的需要,因而顯著提高了多次發(fā)出的命令的總體性能。
您還可以用 ADO CE 中的 Connection 對象上的 Execute 方法,通過使用 SQL insert、update 和 delete 命令來執(zhí)行數(shù)據(jù)操作。您可以用 ADO.NET 中的 SqlCeCommand 對象,通過使用上述命令來操作數(shù)據(jù),從而獲得良好的性能。但是,您必須手動處理 SQL 語法,這有時可能不太方便。ADO CE 和 ADO.NET 都已經(jīng)輕松地使用結(jié)構(gòu)來執(zhí)行數(shù)據(jù)操作。
在 ADO CE 中,您需要以特定的方式打開 Recordset,以便進行數(shù)據(jù)操作。您提供的命令可能只包含一個表名,并且您需要提供最后一個特定參數(shù)。下面是一個在 ADO CE 中添加、更新和刪除行的代碼示例。
Dim rs As ADOCE.Recordset Set rs = CreateObject("ADOCE.Recordset.3.1") rs.Open "Customers", connection, adOpenDynamic, _ adLockOptimistic, adCmdTableDirect ' INSERT rs.AddNew rs("CustomerID").Value = 1 rs("CompanyName").Value = "My Company" rs.Update ' UPDATE rs.Find "CustomerID=2" rs("CompanyName").Value = "Modified Name" rs.Update ' DELETE rs.Find "CustomerID=3" If Not rs.EOF Then rs.Delete rs.Close
應(yīng)用程序用直接表操作 (adCmdTableDirect) 的參數(shù)打開一個包含 Customers 表的 Recordset。然后,您可以通過使用用于添加新行 (AddNew)、更新已添加或已更改的行 (Update) 和移除行 (Delete) 的 Recordset 內(nèi)置功能來操作數(shù)據(jù)。
Visual Basic .NET 中的相應(yīng)代碼如下所示。
Dim da As New SqlCeDataAdapter("SELECT* FROM Customers", _ connection) Dim cb As New SqlCeCommandBuilder(da) da.InsertCommand = cb.GetInsertCommand() da.UpdateCommand = cb.GetUpdateCommand() da.DeleteCommand = cb.GetDeleteCommand() Dim ds As DataSet= New DataSet da.Fill(ds, "Customers") ' INSERT Dim dr As DataRow = ds.Tables("Customers").NewRow() dr("CustomerID") = 1 dr("CustmerName") = "My Company" ds.Tables("Customers").Rows.Add(dr) ' UPDATE dr = ds.Tables("Customers").Select("CustomerID=2")(0) dr("CustomerName") = "Modified Name" ' DELETE dr = ds.Tables("Customers").Select("CustomerID=3")(0) dr.Delete() da.Update(ds, "Customers")
這里,應(yīng)用程序首先通過向構(gòu)造函數(shù)傳遞 select 命令和連接,初始化一個新的 SqlCeDataAdapter。您可以使用 SqlCeCommandBuilder 對象,根據(jù)數(shù)據(jù)適配器中的 select 命令生成需要的數(shù)據(jù)操作命令(insert、update 和 delete)。然后,這些命令在數(shù)據(jù)適配器中得到設(shè)置;稍后,當需要在數(shù)據(jù)庫中保存對 DataSet 中的行所做的更改時,數(shù)據(jù)適配器將使用這些命令來操作數(shù)據(jù)。請注意 ADO.NET 模型是如何通過數(shù)據(jù)適配器達到更高的斷開程度的;它充當完全斷開的 DataSet 和數(shù)據(jù)庫之間的智能鏈接。DataSet 不需要任何指向數(shù)據(jù)庫的連接,并且當您用數(shù)據(jù)填充 DataSet 以后,您可以關(guān)閉數(shù)據(jù)適配器。然后,您可以操作 DataSet;當您完成該操作以后,您可以創(chuàng)建一個新的數(shù)據(jù)適配器來更新數(shù)據(jù)庫。由于有了新的數(shù)據(jù)操作模型,因此通過 ADO.NET 可以完成的工作比通過 ADO CE 可能完成的工作多得多。
在 C# 中,相同的代碼如下所示。
SqlCeDataAdapterda = new SqlCeDataAdapter( "SELECT* FROM Customers", connection); SqlCeCommandBuildercb = new SqlCeCommandBuilder(da); da.InsertCommand = cb.GetInsertCommand(); da.UpdateCommand = cb.GetUpdateCommand(); da.DeleteCommand = cb.GetDeleteCommand(); DataSetds = new DataSet(); da.Fill(ds, "Customers"); // INSERT DataRow dr = ds.Tables["Customers"].NewRow(); Dr["CustomerID"] = 1; Dr["CustomerName"] = "My Company"; ds.Tables["Customers"].Rows.Add(dr); // UPDATE dr = ds.Tables["Customers"].Select("CustomerID=2")[0]; dr["CustomerName"] = "Modified Name"; // DELETE dr = ds.Tables["Customers"].Select("CustomerID=3")[0]; dr.Delete(); da.Update(ds, "Customers");
迄今為止,本文已經(jīng)討論了讀取和操作數(shù)據(jù)的方式。接下來,本文將討論兩個數(shù)據(jù)庫中間件實現(xiàn)中的 SQL 支持中的一些差異。實際上,ADO CE 在以前的工具中實現(xiàn)了 SQL 支持,而即使 ADO.NET 對 SQL 有一些支持,SQL Server CE 本身也支持大多數(shù) SQL 語法。
作為 Pocket PC 程序員,您很快就會發(fā)現(xiàn)新工具中 SQL 支持的豐富性 — 包括 SQL 的數(shù)據(jù)操作語言 (DML) 和數(shù)據(jù)定義語言 (DDL) 這兩個部分。例如,在 ADO CE 中,當您需要知道表中的行數(shù)時,您必須打開一個帶有從該表中加載的所有實際行的 Recordset 對象。在 ADO.NET 中,您可以簡單地查詢數(shù)據(jù)庫表的行數(shù) (SELECT COUNT(*) FROM Customers),并且在單個值中獲得結(jié)果(通過 SqlCeCommand 對象上的 ExecuteScalar 方法)。
為了幫助您直觀地了解新工具對于 SQL 的擴展支持,圖 1 列出了 ADO CE 和 SQL Server CE 中的保留字。

圖 1. ADO CE 和 SQL Server CE 中的 SQL 保留字。
左邊一列包含 ADO CE 中的保留字,右邊的六個列包含 SQL Server CE 中的保留字。有關(guān)詳細信息,請瀏覽 SQL Reference in the SQL Server CE Helpfile(稱為聯(lián)機圖書),或者瀏覽 Visual Studio .NET Help 中的這一內(nèi)容。
從 eMbedded Visual Basic 遷移到 Visual Basic .NET 和 C#
Moving from eMbedded Visual Basic to Visual Basic .NET 一文討論了有關(guān)從 eMbedded Visual Basic 遷移到 Visual Basic .NET 的大多數(shù)常規(guī)問題。該文章的“Working with Databases”部分包含的示例代碼描述了在使用 SQL Server CE 時,如何將代碼從 eMbedded Visual Basic 遷移到 Visual Basic .NET。
它介紹了 Visual Basic .NET 和 C# 這兩個版本的遷移代碼。這樣做的主要原因是讓更多身為開發(fā)人員的讀者能夠立即從示例代碼中受益。而且,如果您是傳統(tǒng)的 eMbedded Visual Basic 開發(fā)人員并且要開始使用 .NET Compact Framework,則您還應(yīng)該考慮 C#。考慮 C# 的主要原因是:在 .NET 中有如此之多的新功能,以至于您可能發(fā)現(xiàn)可以使用它來獲得一個全新的開始,而無需使用 Visual Basic 遺產(chǎn)。
同步
很多以前的 Pocket PC 應(yīng)用程序借助于 ActiveSync 同步桌面計算機和設(shè)備的數(shù)據(jù)。ActiveSync 包含一些支持,以便您同步數(shù)據(jù)庫以及選擇要在同步操作中包括的表。在 ActiveSync 中,不包含對于將 Microsoft Access 或 SQL Server 2000 數(shù)據(jù)庫與設(shè)備上的 SQL Server CE 數(shù)據(jù)庫進行同步的固有支持。但是,您可以使用 ActiveSync 使設(shè)備可以借助于傳遞連接來連接到桌面計算機。
對于 SQL Server CE,您需要使用不同的模型。SQL Server 2000 將同步功能作為 Web 服務(wù)器的插件予以支持。在 SQL Server CE Server Tools 安裝過程中,在 Internet 信息服務(wù) (IIS) 中設(shè)置了一個虛擬目錄。該虛擬目錄包含一個稱為 SQL Server CE Server Agent 的文件 (sscesa20.dll),您可以通過 HTTP 請求來調(diào)用它,以便與 SQL Server 2000 同步數(shù)據(jù)。在客戶端,可以使用 SQL Server CE Client Agent,它包含用于合并復制(設(shè)置數(shù)據(jù)訂閱)和遠程數(shù)據(jù)訪問 (RDA) 的功能。有關(guān)合并復制的詳細信息,請參閱 SQL Server CE Help(聯(lián)機圖書);該文章集中討論了如何通過使用 RDA 來同步數(shù)據(jù)。
即將問世的示例(本文中的大多數(shù)代碼示例都以它為基礎(chǔ))使用一個源自 Access 的數(shù)據(jù)庫。Access 數(shù)據(jù)庫被逐個表地導出到 SQL Server 2000,而 Access 中提供的功能被導出到 ODBC 數(shù)據(jù)源 — 在本例中,為 SQL Server 2000 數(shù)據(jù)庫。(有關(guān)如何導出 Access 數(shù)據(jù)庫的詳細信息,請參閱 Access 幫助或 How To Convert an Access Database to SQL Server。)下一步是通過使用 RDA 中的 Pull 方法,將表從 SQL Server 2000 下載到 SQL Server CE 數(shù)據(jù)庫,如下面的代碼所示。
Dim localDatabase As String = "\MobileSales.sdf" Dim localConnectionString As String = "Data Source=" + localDatabase Dim remoteConnectionString As String = "Provider=sqloledb;" + _ "Data Source=(local);Initial Catalog=MobileSales;" + _ "Integrated Security=SSPI;" Dim tables() As String = New String() {"Customers", "Orders", "Products"} If File.Exists(localDatabase) Then File.Delete(localDatabase) End If Dim engine As New SqlCeEngine(localConnectionString) engine.CreateDatabase() engine.Dispose() Dim rda As New SqlCeRemoteDataAccess() rda.InternetUrl = "http://server/ssce/sscesa20.dll" rda.LocalConnectionString = localConnectionString Dim table As String For Each table In tables Try rda.Pull(table, "SELECT* FROM [" + table + "]", _ remoteConnectionString, _ RdaTrackOption.TrackingOffWithIndexes, "ErrorTable") Catch ex As SqlCeException MessageBox.Show(ex.Message); End Try Next rda.Dispose()
本地連接字符串指向?qū)⒁獎?chuàng)建 SQL Server CE 數(shù)據(jù)庫文件的位置,而遠程連接字符串則指向應(yīng)用程序?qū)闹袡z索數(shù)據(jù)的 SQL Server 2000 數(shù)據(jù)庫 (MobileSales)。如果數(shù)據(jù)庫文件已經(jīng)存在,則應(yīng)用程序會刪除它,然后,應(yīng)用程序通過使用 SqlCeEngine 對象創(chuàng)建數(shù)據(jù)庫。應(yīng)用程序設(shè)置 RDA (SqlCeRemoteDataAccess) 對象,以指向服務(wù)器或桌面計算機中駐留 SQL Server CE Server Agent (sscesa20.dll) 的虛擬目錄 (ssce)。應(yīng)用程序使用表數(shù)組將表從 SQL Server 2000 拉到剛剛創(chuàng)建的本地 SQL Server CE 數(shù)據(jù)庫中。
請注意,虛擬目錄使用匿名訪問,并且,通過指定的連接字符串給予 IIS 中的匿名用戶(例如,IUSR_MACHINENAME)訪問 SQL Server 2000 中數(shù)據(jù)庫的權(quán)利。在實際方案中,虛擬目錄很可能需要指定的用戶,并且隨后在 RDA 對象(在它的 InternetLogin 和 InternetPassword 屬性中)上設(shè)置憑據(jù)。
還要注意,應(yīng)用程序指定用于下載索引和關(guān)閉跟蹤的選項 (TrackingOffWithIndexes)。如果指定了跟蹤,則應(yīng)用程序以后可以使用 RDA 對象的 Push 方法將表推送回服務(wù)器,以便將更改添加到 SQL Server 2000 數(shù)據(jù)庫中。有關(guān)詳細信息,請參閱 SQL Server CE Help(聯(lián)機圖書)。
在 C# 中,代碼如下所示。
string localDatabase = @"\MobileSales.sdf"; string localConnectionString = "Data Source=" + localDatabase; string remoteConnectionString = @"Provider=sqloledb;" + "Data Source=(local);Initial Catalog=MobileSales;" + "Integrated Security=SSPI;"; string[] tables = new string[] { "Customers", "Orders", "Products" }; if(File.Exists(localDatabase)) File.Delete(localDatabase); using(SqlCeEngineengine = new SqlCeEngine(localConnectionString)) engine.CreateDatabase(); using(SqlCeRemoteDataAccessrda = new SqlCeRemoteDataAccess()) { rda.InternetUrl = "http://server/ssce/sscesa20.dll"; rda.LocalConnectionString = localConnectionString; foreach (string table in tables) { try { rda.Pull(table, "SELECT* FROM [" + table + "]", remoteConnectionString, RdaTrackOption.TrackingOffWithIndexes, "ErrorTable"); } catch (SqlCeExceptionex) { //MessageBox.Show(ex.Message); showErrors(ex); } } }
您也可以不使用上述代碼,而是繼續(xù)與桌面計算機上的 Access 數(shù)據(jù)庫進行同步,或者用另一個數(shù)據(jù)庫進行復制。常規(guī)解決方案是在服務(wù)器(或桌面計算機)上設(shè)置 XML Web 服務(wù)。該 Web 服務(wù)可以發(fā)布方法,以供在數(shù)據(jù)庫中執(zhí)行數(shù)據(jù)操作的設(shè)備使用。
下面的代碼示例從 XML Web 服務(wù)(作為 Visual Studio .NET 中的 ASP.NET Web 服務(wù)項目創(chuàng)建)中使用原始的 Access 數(shù)據(jù)庫。
<WebMethod> _ Public Function Sync(ByVal newCustomerNames() As String) As DataSet ' Set up connection and data adapter OleDbConnection cn = New OleDbConnection(+ "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;" + "Data Source=C:\Mobile Sales.mdb") cn.Open() ' Set up command and insert new customers Dim cmd As New OleDbCommand( "INSERT INTO Customers (CustomerName) VALUES(?)", cn) cmd.Parameters.Add("?", DbType.String) For Each newCustomerName As String In newCustomerNames cmd.Parameters(0).Value = newCustomerName cmd.ExecuteNonQuery Next ' Get all customers Dim da As New OleDbDataAdapter("SELECT* FROM Customers", cn) Dim ds As DataSet= New DataSet() da.Fill(ds, "Customers") ' Send back all customers Return ds End Function
XML Web 服務(wù)方法(Web 方法)采用新客戶的名稱數(shù)組作為參數(shù)。在設(shè)置了連接和命令對象以后,應(yīng)用程序使用該數(shù)組創(chuàng)建新的客戶行。請注意代碼是如何使用參數(shù)來提高插入多個客戶的速度的。還要注意,使用設(shè)備上的命令對象(通過 .NET Compact Framework 中的 ADO.NET)完成該操作的語法是非常類似的。然后,應(yīng)用程序再次查詢數(shù)據(jù)庫,并且將所有客戶名稱(包括新名稱)返回到設(shè)備。注意這就是同步功能,并且需要將所有客戶返回到該設(shè)備,因為當該設(shè)備斷開連接時,其他設(shè)備可能已經(jīng)添加了客戶。
在 C# 中,代碼如下所示。
[WebMethod] public DataSetSync(string[] newCustomerNames) { // Set up connection and data adapter OleDbConnection cn = new OleDbConnection( + "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;" + @"Data Source=C:\Mobile Sales.mdb"); cn.Open(); // Set up command and insert new customers OleDbCommand cmd = new OleDbCommand( "INSERT INTO Customers (CustomerName) VALUES(?)", cn); cmd.Parameters.Add("?", DbType.String); foreach(string newCustomerName in newCustomerNames) { cmd.Parameters[0].Value = newCustomerName; cmd.ExecuteNonQuery(); } // Get all customers OleDbDataAdapter da = new OleDbDataAdapter( "SELECT* FROM Customers", cn); DataSetds = new DataSet(); da.Fill(ds, "Customers"); // Send back all customers (including new) return ds; }
采用類似的方式,應(yīng)用程序可以訪問任何在服務(wù)器上具有 ADO.NET 的符合 OLE DB 的數(shù)據(jù)源 — 或其他具有自己的托管提供程序的數(shù)據(jù)庫(例如,Oracle)。
Mobile Sales .NET 示例
Mobile Sales .NET 示例演示了如何將用 eMbedded Visual Basic 編寫并且使用 ADO CE 訪問 Pocket Access 數(shù)據(jù)庫中的數(shù)據(jù)的應(yīng)用程序遷移到 .NET Compact Framework,以便它使用 ADO.NET 訪問 SQL Server CE 數(shù)據(jù)庫中的數(shù)據(jù)。該示例隨附在 Larry Roof 于 2001 年撰寫的文章 Data To Go 中。
Mobile Sales .NET 示例是用 Visual Studio.NET2003 創(chuàng)建的。它由單個窗體組成,如圖 2 所示。

圖 2. Mobile Sales .NET
其方案是一個訪問很多個客戶的送貨司機。在每個站點,他都會取走一份定單。對于每份定單,他都會選擇產(chǎn)品,輸入數(shù)量,然后點擊 Add。如果該司機出了錯,則他會選擇項行,然后點擊 Delete。要保存定單,該司機可以點擊 Save this order 菜單命令;然后,他可以接著處理下一份定單。當該司機保存了所有客戶定單時,他退出應(yīng)用程序。該示例的工作方式與原始的 eMbedded Visual Basic 示例 (Data To Go) 相同。
熱詞搜索:
上一篇:信息安全新理念 趨勢科技專家服務(wù)說明
下一篇:看燈識故障,ADSL故障排除技巧四則
