从Pocket Access向SQL Server CE进行数据库迁移
2007-12-27 15:32:28 来源:WEB开发网摘要:本文讨论有关将用 eMbedded Visual Basic 编写的 Pocket PC 应用程序迁移到 .NET Compact Framework 的问题。迁移包括从使用 ADO CE 访问 Pocket Access 数据库中的数据更改为使用 ADO.NET 访问 SQL Server CE 中的数据。本文提供了 Visual Basic 和 C# 两种版本的示例代码。
请从 Microsoft 下载中心下载 Download Database Migration from CEDB to SQL Server CE.msi。
简介
无论您是已经决定将应用程序和数据从以前的 Pocket PC 工具(Microsoft eMbedded Visual Basic 和 Pocket Access)迁移到目前的技术(Microsoft .NET Compact Framework 和 Microsoft SQL Server CE),还是正在考虑这一决定,您都需要研究这一迁移的一些困难的理由。
第一个理由是您的设备将提高性能。在设备处理器(即使是最新的最优秀的处理器)上,性能无疑非常重要。在 SQL Server CE 中正确地设置数据库(通过适当的密钥、索引等)以后,它的性能将完全超过 Pocket Access — 有时可以超过好多倍。
第二个理由是 SQL Server CE 中更为丰富的类型系统将使您的设备能够更有效地存储数据。您可以存储在 Pocket Access 中的所有内容都可以存储在 SQL Server CE 中(不止如此)。因为该类型系统是 SQL Server 2000 的类型系统的干净子集,所以同步也会更加容易。
第三个理由是当前的数据访问中间件 (ADO.NET) 将为您提供更多的功能,以使您除了操作数据的定义以外,还可以读取和操作数据本身。新增的且本来断开的模型(由 DataSet 表明)使您在数据的使用方式方面具有更多的自由。可以将 DataSet 发送到 XML Web 服务(当您通过 ASP.NET 创建 XML Web 服务时,DataSet 类型将受到天然支持)。您可以将 DataSet 作为 XML(包含 XML 架构信息,或者在单独的文件中)存储到文件系统中(可以将 XML 从相同的文件重新读取到 DataSet 中)。
最后一个理由是,除了数据操作以外,更加丰富的 SQL 语法还使您在读取数据时具有更多的选择(使用子查询、外部联接等)。以前,您需要在检索 Recordset 之后的代码中实现大量逻辑,而现在您可以直接在它所属的 SQL 命令中完成该工作。在以前的代码中,完成诸如通过 LTRIM 或 CASE...WHEN...THEN...ELSE...END 语句格式化 SELECT 语句中的列的工作要困难得多,并且通常会更慢。
当从以前的 Pocket PC 应用程序进行的迁移同时涉及到数据和代码的迁移时,您可以在下列三个不同的级别执行迁移:
• |
数据库 |
• |
数据库中间件 |
• |
源代码 |
在数据库级别,可以将数据和代码从 Pocket Access 迁移到 SQL Server CE。主要差异与受支持的数据类型有关。当您迁移数据访问代码时,数据库中间件中的差异主要与受支持的对象以及使用这些对象的语法有关。通常,当您迁移源代码时,差异同时与不同的语言以及受支持的类库有关。下列各部分将描述不同级别之间的差异。
从 Pocket Access 迁移到 SQL Server CE
通常,以前的 Pocket PC 应用程序中的数据源自桌面计算机的 Microsoft Access 数据库。当需要进行桌面计算机复制时,通常会借助于 Microsoft ActiveSync 中内置的同步功能在桌面计算机和设备之间复制这些数据。当数据迁移到 SQL Server CE 时,第一步是将现有的 Access 数据库迁移到 SQL Server 2000。
您可以从 Access 内部执行该迁移,方法是通过连接到 SQL Server 2000 数据库的开放式数据库连接 (ODBC) 数据源来导出表。然后,您可以通过使用远程数据访问 (RDA) 将 SQL Server 2000 中的数据复制到设备上的 SQL Server CE。有关如何完成该复制的详细信息,请参阅本文中的“同步”一节。
表 1 显示了每个数据库支持的不同数据类型的映射。
表 1. 数据类型映射 | |||
Access 数据类型 | 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 数据类型,并且因为 SQL Server CE 支持(不用转换)导出中生成的所有类型,所以迁移过程中不会丢失任何信息。
从 ADO CE 迁移到 ADO.NET
ActiveX Data Objects for Windows CE (ADO CE) 是作为 ADO 的设备版本创建的,并且第一个版本 (3.0) 只支持 Pocket Access。在创建 SQL Server CE 时,更新了 ADO CE 以支持它。尽管很多以前的 Pocket PC 应用程序使用 ADO CE(3.0) 的第一个版本来访问 Pocket Access 数据库,但本节中的信息只与最新版本 (3.1) 有关。不过,下列代码示例也应该适用于 ADO CE .0。
ADO CE 支持下列对象:Recordset、Field(和集合)、Connection 和 Error(和集合)。但是,ADO CE 不支持完整(桌面)ADO 实现中包含的 Command 对象。作为 ADO CE 的扩展,ADO XCE 包含管理数据库的功能,如操作表、字段和其他数据库对象。
.NET Compact Framework 中的 ADO.NET 是完整 .NET Framework 数据访问中间件的设备版本。您可以在“System.Data.SqlServerCe”命名空间中找到 ADO.NET for SQL Server CE,它通常被称为 SQL Server CE 的托管提供程序。该托管提供程序中最重要的对象是:SqlCeConnection(用于连接到数据库)、SqlCeDataAdapter(用于访问数据库中的数据)、SqlCeCommandBuilder(用于生成 SQL 命令以便在数据库中保存数据)、SqlCeCommand(用于向数据库发出 SQL 命令)、SqlCeDataReader(用于从数据库中快速地顺序读取数据)、SqlCeEngine(用于管理数据库)以及 SqlCeException(用于错误处理)。有关 ADO CE 和 ADO.NET 的详细信息,请参阅 Microsoft Visual Studio .NET 帮助文件。
在 ADO CE 中执行的多个重要操作可以通过 ADO.NET 来完成。首先,您需要打开数据库连接。在 ADO CE 中,您可以按如下方式打开数据库。
Dim connection AS ADOCE.Connection
Set connection = CreateObject("ADOCE.Connection.3.1")
connection.ConnectionString = "Data Source=MyDatabase.cdb"
connection.Open
您还可以将连接字符串作为连接的 Open 方法的参数提供。调用 Connection 对象上的 Close 方法可以关闭该连接。
如果您要使用 ADO.NET 和 Visual Basic .NET,则您可以按如下方式打开数据库连接。
Dim connection As SqlCeConnection
connection = New SqlCeConnection("Data Source=MyDatabase.sdf")
connection.Open()
与 ADO CE 类似,该连接的 Close 方法可以关闭该连接。
在 C# 中,相同的代码如下所示。
SqlCeConnectionconnection
connection = new SqlCeConnection(@"Data Source=MyDatabase.sdf");
connection.Open();
因为越早考虑错误处理越好,所以您可以查看 ADO CE 中是如何处理错误的。首先,您需要按如下方式设置错误处理程序:
On Error Resume Next
Err.Clear
在应用程序执行每个数据库命令之后,Connection 对象上的错误集合 (Errors) 包含已经发生的任何错误。您可以通过使用以下代码让应用程序报告任何错误。
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 数据库时,ADO CE 中的错误对象还支持本机错误 (NativeError) 和错误源 (Source) 的属性。
在 Visual Basic .NET 中,您可以通过使用 Try Catch 结构处理错误。下面是用于捕获和报告 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 中,发生的异常(错误)包含的信息要比 ADO CE 提供的信息多得多。该信息帮助开发人员更快地查找程序错误,并且还在处理每个异常方面提供了更多的控制。首先,应用程序在消息框中报告任何内部异常,然后,应用程序在每个错误的消息框中报告(通过详细信息)异常对象 (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("
Message : " + error.Message);
s.Append("
Minor Err.: " + error.NativeError);
s.Append("
Source : " + error.Source);
foreach (int numericErrorParameter in
error.NumericErrorParameters)
if(numericErrorParameter != 0)
s.Append("
Num. Par. : " + numericErrorParameter);
foreach (string errorParameter in error.ErrorParameters)
if(errorParameter.Length > 0)
s.Append("
Err. Par. : " + errorParameter);
MessageBox.Show(s.ToString());
s.Remove(0, s.Length);
}
}
既然您具有连接并且可以处理返回的错误,那么您就可以开始与数据库交互了。最重要的操作是在数据库中查询数据。在 ADO CE 中,可以用下列两种方式查询数据库:通过使用 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)
使用数据适配器的相应 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")
在前面的代码中,通过将数据库 (SQL) 命令和 Connection 对象作为构造函数的参数进行传递,创建了一个新的数据适配器对象 (da)。然后,通过使用该数据适配器上的 Fill 方法为 DataSet (ds) 填充了数据。Fill 方法的第二个参数设置了 DataSet 中刚刚检索的表的名称。在后台,数据适配器使用 SqlCeCommand 对象(在它的 SelectCommand 属性中)查询数据库。
在 C# 中,代码如下所示。
string sql = "SELECT* FROM Customers";
SqlCeDataAdapterda = new SqlCeDataAdapter(sql, connection);
DataSetds = new DataSet;
da.Fill(ds, "Customers");
ADO.NET 中提供的另一种读取数据的方式是 SqlCeDataReader。您可以使用它以一种非常高效的方式来顺序读取数据。当性能很重要以及数据量很高时,您应该考虑该选项。以下代码显示了一个有关如何使用 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
当从命令对象创建读取器时,使用第二个列 (dr(1)) 向列表框 (ListBox1) 中添加行。
在 C# 中,代码如下所示。
string sql = "SELECT* FROM Customers";
SqlCeCommandcmd = new SqlCeCommand(sql, connection);
SqlCeDataReaderdr = cmd.ExecuteReader();
在 ADO CE 中,唯一受支持的执行不返回任何数据的命令的方式是使用 Connection 对象上的 Execute 方法,然后通过使用以下代码忽略返回值。
connection.Execute("DELETE Customers WHERE CustomerID=1")
在 Visual Basic .NET 中,您可以使用 SqlCeCommand 对象执行命令,如下所示。
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();
您还可以通过向构造函数提供命令文本和连接来创建命令对象。
该命令对象具有 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();
该命令对象还支持参数(但是,它不支持命名参数),您可能发现这在多次使用命令时非常有用,因为参数化查询避免了重复计算查询计划的需要,因而显著提高了多次发出的命令的总体性能。
您还可以用 ADO CE 中的 Connection 对象上的 Execute 方法,通过使用 SQL insert、update 和 delete 命令来执行数据操作。您可以用 ADO.NET 中的 SqlCeCommand 对象,通过使用上述命令来操作数据,从而获得良好的性能。但是,您必须手动处理 SQL 语法,这有时可能不太方便。ADO CE 和 ADO.NET 都已经轻松地使用结构来执行数据操作。
在 ADO CE 中,您需要以特定的方式打开 Recordset,以便进行数据操作。您提供的命令可能只包含一个表名,并且您需要提供最后一个特定参数。下面是一个在 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
应用程序用直接表操作 (adCmdTableDirect) 的参数打开一个包含 Customers 表的 Recordset。然后,您可以通过使用用于添加新行 (AddNew)、更新已添加或已更改的行 (Update) 和移除行 (Delete) 的 Recordset 内置功能来操作数据。
Visual Basic .NET 中的相应代码如下所示。
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")
这里,应用程序首先通过向构造函数传递 select 命令和连接,初始化一个新的 SqlCeDataAdapter。您可以使用 SqlCeCommandBuilder 对象,根据数据适配器中的 select 命令生成需要的数据操作命令(insert、update 和 delete)。然后,这些命令在数据适配器中得到设置;稍后,当需要在数据库中保存对 DataSet 中的行所做的更改时,数据适配器将使用这些命令来操作数据。请注意 ADO.NET 模型是如何通过数据适配器达到更高的断开程度的;它充当完全断开的 DataSet 和数据库之间的智能链接。DataSet 不需要任何指向数据库的连接,并且当您用数据填充 DataSet 以后,您可以关闭数据适配器。然后,您可以操作 DataSet;当您完成该操作以后,您可以创建一个新的数据适配器来更新数据库。由于有了新的数据操作模型,因此通过 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");
迄今为止,本文已经讨论了读取和操作数据的方式。接下来,本文将讨论两个数据库中间件实现中的 SQL 支持中的一些差异。实际上,ADO CE 在以前的工具中实现了 SQL 支持,而即使 ADO.NET 对 SQL 有一些支持,SQL Server CE 本身也支持大多数 SQL 语法。
作为 Pocket PC 程序员,您很快就会发现新工具中 SQL 支持的丰富性 — 包括 SQL 的数据操作语言 (DML) 和数据定义语言 (DDL) 这两个部分。例如,在 ADO CE 中,当您需要知道表中的行数时,您必须打开一个带有从该表中加载的所有实际行的 Recordset 对象。在 ADO.NET 中,您可以简单地查询数据库表的行数 (SELECT COUNT(*) FROM Customers),并且在单个值中获得结果(通过 SqlCeCommand 对象上的 ExecuteScalar 方法)。
为了帮助您直观地了解新工具对于 SQL 的扩展支持,图 1 列出了 ADO CE 和 SQL Server CE 中的保留字。
图 1. ADO CE 和 SQL Server CE 中的 SQL 保留字。
左边一列包含 ADO CE 中的保留字,右边的六个列包含 SQL Server CE 中的保留字。有关详细信息,请浏览 SQL Reference in the SQL Server CE Helpfile(称为联机图书),或者浏览 Visual Studio .NET Help 中的这一内容。
- ››SQL Server 2008 R2 下如何清理数据库日志文件
- ››sqlite 存取中文的解决方法
- ››SQL2005、2008、2000 清空删除日志
- ››SQL Server 2005和SQL Server 2000数据的相互导入...
- ››sql server 2008 在安装了活动目录以后无法启动服...
- ››sqlserver 每30分自动生成一次
- ››sqlite 数据库 对 BOOL型 数据的插入处理正确用法...
- ››sql server自动生成批量执行SQL脚本的批处理
- ››sql server 2008亿万数据性能优化
- ››SQL Server 2008清空数据库日志方法
- ››sqlserver安装和简单的使用
- ››SQL Sever 2008 R2 数据库管理
更多精彩
赞助商链接