设为首页 收藏本站
查看: 1074|回复: 0

[经验分享] 如何将数据导入到 SQL Server Compact Edition 数据库中

[复制链接]

尚未签到

发表于 2016-11-7 07:05:20 | 显示全部楼层 |阅读模式
  一、场景描述
在智能设备(Smart Device)应用程序和智能客户端(Smart Client)应用程序的部署阶段,我们需要对离线数据进行初始化,即将后台数据库服务器中的一些数据,导入到离线数据库中。通常采用两种方式对离线数据进行初始化,第一种是在程序第一次运行时,通过数据同步的方式,把数据从后台下载下来;第二种是将预先准备好的离线数据随应用程序一起部署。
  对于 SQL Server Compact Edition (SQL CE 3.1) 数据库,第一种方式通常可以利用 Remote Data Access (RDA), Merge Replication, Sync Services for ADO.NET (SQL CE 3.5 中新增) 或者自己实现基于 Web Service 的数据同步机制来实现。RDA 和 Merge Replication 最大的缺点是只能连到 SQL Server 数据库,如果 SQL CE 需要跟 Oracle 和DB2等数据库进行数据同步,需要 SQL Server 做“中介”。另外,RDA 没有冲突处理机制,并且每次必须重新下载全部数据;Merge Replication 配置太繁琐了。Sync Services for ADO.NET 目前还在 beta 阶段,beta1 还不支持智能设备应用程序,只支持桌面应用程序。Orcas beta2 刚刚发布,目前还没有下载完毕,不知道有没有性能方面的提升和增加对智能设备应用程序的支持。暂时先对 Sync Services for ADO.NET 保留意见,等我用上 beta2 了再详细介绍。自己实现基于 Web Service 的数据同步机制需要考虑大数据量如何分批次传输和性能问题。总的来说,第一种方式的实现途径很多,如果初始化数据量比较大,并且客户端数量比较多的话,那么将有可能带来漫长的部署过程和一笔巨大的无线网络流量的费用。
  第二种方式可以利用 SQL CE 3.1 对桌面应用程序的支持,预先将 SQL Server, Oracle, DB2, MySQL 等等各种数据库的数据导入到 SQL CE 中,然后通过 ActiveSync 批量将 SQL CE 的数据库文件(*.sdf)拷贝到设备或机器上。以后客户端再通过 Web Service 的方式下载新增/修改/删除的数据来更新本地的离线数据。这样可以节约大量的部署时间和网络通信成本。
  当然并不是第二种方式一定比第一种方式好,这个看具体的实施环境。本文主要介绍的是第二种方式。
  二、技术选择
  既然 SQL CE 3.1 支持桌面应用程序,那么我们可以通过三种方式来准备离线数据:第一,利用 RDA 数据同步;第二,利用 Merge Replication 数据同步;第三,用 ADO.NET 直接从读写数据。第一和第二种方式需要额外的安装和配置,而且只支持 SQL Server 数据库。如果非要在第一和第二种方式中选择的话,我会选择 RDA,因为它配置工作量更少,性能更好,更加灵活。本文选择第三种方式,因为它离两个数据库的距离最近,而且支持多种数据库。
  三、实现原理
  数据导入程序实现起来很简单,不过需要考虑性能。从源数据库读取数据要考虑速度和内存冲击,可以采用 DataSet 或者 DataReader,毫无疑问我们选择 DataReader。将数据写入 SQL CE,通常大家会想到编写一个 SqlCeCommand,然后给 SqlCeCommand 的 CommandText 属性赋上 Insert SQL 语句“insert into Products values(@ProductID, @ProductName)”,接着一边读取数据,一边给参数赋值并写入 SQL CE 数据库中……大家冷落了一个叫 SqlCeResultSet 的对象,它是 SQL Mobile 增加的数据访问对象。SqlCeResultSet 提供了一个功能的组合:DataSet 的可更新性和可滚动性以及与 SqlCeDataReader 类似的性能。SqlCeResultSet 类继承了 SqlCeDataReader 类,因此它拥有 SqlCeDataReader 类所有的特性。利用 SqlCeResultSet 可以实现高性能的数据读取和写入。
  四、代码和分析
///<summary>
///将源数据库表的数据复制到SQLServerCompactEdition数据库的表中。
///</summary>
///<paramname="srcConnection">源数据库连接接对象。</param>
///<paramname="destConnection">目标SQLServerCompactEdition数据库连接对象。</param>
///<paramname="queryString">源数据的查询语句。</param>
///<paramname="destTableName">目标数据库表名称。</param>
///<remarks>本方法假设目标SQLServerCompactEdition数据库的表已经存在。</remarks>
publicstaticvoidCopyTable(
IDbConnectionsrcConnection,
SqlCeConnectiondestConnection,
stringqueryString,
stringdestTableName)
{
IDbCommandsrcCommand
=srcConnection.CreateCommand();
srcCommand.CommandText
=queryString;

SqlCeCommanddestCommand
=destConnection.CreateCommand();
destCommand.CommandType
=CommandType.TableDirect;//基于表的访问,性能更好
destCommand.CommandText=destTableName;
try
{
IDataReadersrcReader
=srcCommand.ExecuteReader();

SqlCeResultSetresultSet
=destCommand.ExecuteResultSet(
ResultSetOptions.Sensitive
|//检测对数据源所做的更改
ResultSetOptions.Scrollable|//可以向前或向后滚动
ResultSetOptions.Updatable);//允许更新数据

object[]values;
SqlCeUpdatableRecordrecord;
while(srcReader.Read())
{
//从源数据库表读取记录
values=newobject[srcReader.FieldCount];
srcReader.GetValues(values);

//把记录写入到目标数据库表
record=resultSet.CreateRecord();
record.SetValues(values);
resultSet.Insert(record);
}

srcReader.Close();
resultSet.Close();
}
catch(Exceptionex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}

  由于 CopyTable 函数的源数据库连接参数采用的是 IDbConnection 接口,所以该方法可以支持多种源数据库。代码中还利用 IDataReader.GetValues(object[] values) 和 SqlCeUpdatableRecord.SetValues(object[] values) 更方便的读取和写入数据。
  在使用 CopyTable 函数之前必须预先创建好 SQL CE 数据库的表结构,并且 SQL CE 数据库的表结构必须跟 queryString参数(select SQL 语句)的查询结果的表结构对应。
  通过下面的代码使用 CopyTable 函数:
//创建源SQLServer数据库连接对象
stringsrcConnString="DataSource=(local);InitialCatalog=Northwind;IntegratedSecurity=True";
SqlConnectionsrcConnection
=newSqlConnection(srcConnString);

//创建目标SQLServerCompactEdition数据库连接对象
stringdestConnString=@"DataSource=C:\Northwind.sdf";
SqlCeConnectiondestConnection
=newSqlCeConnection(destConnString);

VerifyDatabaseExists(destConnString); //创建数据库结构

srcConnection.Open();
destConnection.Open();

//复制数据
CopyTable(srcConnection,destConnection,"SELECT*FROMProducts","Products");
CopyTable(srcConnection,destConnection,
"SELECT*FROMEmployees","Employees"
);

srcConnection.Close();
destConnection.Close();

  五、创建数据库结构
  上面说到在使用 CopyTable 函数之前 SQL CE 数据库必须存在并且表结构都创建好。我们现在就来编写创建数据库结构的代码。首先创建一个名为 DbSchema.sql 的文件,并编写 Northwind 数据库中的 Products 和 Employees 表的创建脚本:
CREATETABLEProducts(
ProductID
intNOTNULLCONSTRAINTPK_ProductsPRIMARYKEY,
ProductName
nvarchar(40)NOTNULL,
SupplierID
intNULL,
CategoryID
intNULL,
QuantityPerUnit
nvarchar(20)NULL,
UnitPrice
moneyNULL,
UnitsInStock
smallintNULL,
UnitsOnOrder
smallintNULL,
ReorderLevel
smallintNULL,
Discontinued
bitNOTNULL
)
GO
CREATETABLEEmployees(
EmployeeID
intNOTNULLCONSTRAINTPK_EmployeesPRIMARYKEY,
LastName
nvarchar(20)NOTNULL,
FirstName
nvarchar(10)NOTNULL,
Title
nvarchar(30)NULL,
TitleOfCourtesy
nvarchar(25)NULL,
BirthDate
datetimeNULL,
HireDate
datetimeNULL,
Address
nvarchar(60)NULL,
City
nvarchar(15)NULL,
Region
nvarchar(15)NULL,
PostalCode
nvarchar(10)NULL,
Country
nvarchar(15)NULL,
HomePhone
nvarchar(24)NULL,
Extension
nvarchar(4)NULL,
Photo
imageNULL,
Notes
ntextNULL,
ReportsTo
intNULL,
PhotoPath
nvarchar(255)NULL
)
GO
  这段 SQL 语句不能直接在 SQL CE 上执行的,我们需要进行一些字符串的处理。现在将该文件添加到 Visual Studio 2005 的项目资源中。

DSC0000.png

DSC0001.png

并添加执行这段 SQL 创建数据库表结构的方法:
publicstaticvoidVerifyDatabaseExists(stringconnectionString)
{
using(SqlCeConnectionconnection=newSqlCeConnection(connectionString))
{
if(!File.Exists(connection.Database))
{
using(SqlCeEngineengine=newSqlCeEngine(connection.ConnectionString))
{
engine.CreateDatabase();

string[]commands=Properties.Resources.DbSchema.Split(
newstring[]{"GO"},StringSplitOptions.RemoveEmptyEntries);

SqlCeCommandcommand
=newSqlCeCommand();
command.Connection
=connection;
connection.Open();
for(inti=0;i<commands.Length;i++)
{
command.CommandText
=commands;
command.ExecuteNonQuery();
}
}
}
}
}

  六、总结
  性能测试的结果会因为环境的不同而有一些出入,我想留给大家去做会更有意义。不过我相信这是当前性能比较好的向 SQL CE 导入数据的方法之一。目前需要预先创建好 SQL CE 的表结构是美中不足的地方,我会在后续文章中实现一个自动根据查询结果生成创建 SQL CE 表结构的 SQL 语句的代码,其实并不难。

参考:
ADO.NET Generic Copy Table Data Function
Creating your SQL Server Compact Edition database and schema in code

示例代码下载:sqlce_data_import.rar

作者:黎波
博客:http://upto.cnblogs.com/
日期:2007年7月29日

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-296702-1-1.html 上篇帖子: 《Microsoft Sql server 2008 Internals》读书笔记--第七章Special Storage(4) 下篇帖子: SQL Server中SMO备份数据库进度条不显示?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表