社区编辑申请
注册/登录
如何实现Windows Mobile下C++访问SqlCe的封装
移动开发
这里讲述在Windows Mobile和Wince下,Native C++访问SqlCe的封装类的实现。希望本文能对大家有所帮助。

在手机下,进行数据库开发,一般都要使用轻量级数据库。这里介绍的是如何实现Windows Mobile下C++访问SqlCe的封装。

背景

进行Windows Mobile的应用的开发,很多时候需要对数据库进行访问,存储和读取。可是微软没有为Native C++提供象ADO.NET下的封装,所以我自己封装了一个SqlCe访问类。

简述

本文讲述在Windows Mobile和Wince下,Native C++访问SqlCe的封装类的实现。由于微软没有为C++提供像ADO.NET的封装,为Native C++访问SqlCe制造了一定的难度,因此对OleDB访问SqlCe进行封装,方便使用SQL语句对SqlCe进行操作。

SqlCe访问技术概述

ADO.NET

.NET Compact Framework逐渐成为Windows Mobile和Wince的开发的主流,微软为CF.NET提供了ADO.NET访问SqlCe,对SqlCe的访问封装在System.Data.SqlServerCe下,和其他数据库(SQL Server, Oracle)访问基本兼容,但是不支持DbProviderFactory。例如下面的代码不能通过编译,因为没有SqlCeProviderFactory类。

DbProviderFactory factory = SqlCeProviderFactory.Instance;我之前封装了一个ADO.NET的SqlCe访问类,可以参考 .NET Compact Framework下SQL CE的使用 和 实现了SqlCeHepler的单元测试类见.NET Compact Framework下的单元测试。

OleDb

在Native的世界,可以通过OleDb来访问SqlCe。OleDb封装在sqlceoledb35.dll下,使用OleDb需要安装一个Cab包如下:

C:\Program Files\Microsoft SQL Server Compact Edition\v3.5\Devices\wce500\armv4i\sqlce.repl.ppc.wce5.armv4i.CAB上述路径根据平台有所不同。

注意上述sqlceoledb35.dll只是支持SqlCe 3.5,微软对不同版本的SqlCe的兼容性不是很好,可以参考 SQL Server Express和SQL Server Compact的应用 和 .NET Campact Framework下SQL CE兼容性问题 了解SqlCe的历史我兼容性问题。

本文后续会重点讲述OleDb。

ADO

在Windows Mobile和Wince平台,微软官方不支持ADO。但是有一个社区实现,可以参考 A set of ADOCE classes。我没有试过,所以不好评论。

实现

下面讲述如何基于OleDb实现对SqlCe的访问。

文档和Samples

微软提供了在线文档,可以在 Microsoft SQL Server Compact 3.5 Books Online and Samples下载。上述链接只是包含在线文档,没有提供例子程序的,所以这个名字有点骗人感情之嫌。虽然提供了在线文档,但是文档的质量不高,有些细节没讲,例如调用ICommand::Execute的入口参数就没有讲,我做的时候只能自己试。

虽然上面的链接不提供Samples,但是我们还有另外一个方法取得Samples。在

C:\Program Files\Microsoft SQL Server 2005 Mobile Edition\Samples\NorthwindOleDb下可以得到Sample代码,前提是安装了Microsoft SQL Server 2005 Mobile Edition。但是要注意不同SqlCe版本实现有所不同,这个代码要结合上面的Online book修改才行。

基于SQL语句的实现

微软的例子程序NorthwindOleDb提供了通过OleDb访问SqlCe的方法,但是不提供对SQL语句的封装,直接对表的访问效率比较高,但是也有很大的不便性。因为每个操作都单独封装一个函数,每个函数大概至少需要100行代码,而且有指针等资源的分配,释放等操作,一旦没有处理好就发生内存泄漏了。所以我偏向于使用统一的SQL语句接口对SqlCe进行操作,虽然牺牲了点性能,却提供了方便性。下面是当前版本的封装类。这个类是基于João Paulo Figueira 的OleDbClientLib3实现的。

基于SQL语句的实现

 

打开关闭

  1. bool Open(const CString& dbPath);  
  2. void Close(); 

上面为打开和关闭SqlCe数据库链接的操作,这里实现为长链接,也就是不调用Close()的话,数据库的Session一直链接着,这样的好处是缩短访问时间。

新建删除

  1. bool CreateDatabase(const CString& dbPath);  
  2. bool DeleteDatabase(const CString& dbPath); 

由于SqlCe是in-process数据库,物理上表现为就一个文件,可以方便新建和删除,上述接口就是新建和删除SqlCe数据库,新建后自动打开数据库的Senssion了。

增删改操作

  1. int  ExecuteNonQuery(const CString& sql); 

把增删改的语句调用ExecuteNonQuery()执行就可以了。

  1. SqlCeHelper db;HRESULT hr = db.Open(DB_FILE_NAME);  
  2. if(hr < 0){    CString cstr = db.GetErrorsMessage();   
  3.    char* str = new char[cstr.GetLength()+1];      
  4. sprintf(str, "%S", cstr);     
  5.  FAIL(str);      
  6. delete str;}CString sqlStr;for(int i=0; i<max; ++i)  
  7. {    SYSTEMTIME currentTime;    
  8.       GetLocalTime(¤tTime);   
  9.    sqlStr.Format(L"INSERT INTO T1 (F1, F2, F3) VALUES(%d, 'STR%d', '%d-%d-%d %d:%d:%d')",         i, i, currentTime.wYear, currentTime.wMonth, currentTime.wDay, currentTime.wHour, currentTime.wMinute, currentTime.wSecond);    
  10.   hr = db.ExecuteNonQuery(sqlStr);   
  11.    if(hr < 0)     
  12.  {        CString cstr = db.GetErrorsMessage();   
  13.        char* str = new char[cstr.GetLength()+1];   
  14.        sprintf(str, "%S", cstr);      
  15.     FAIL(str);          
  16. delete str;   
  17.    }  
  18. }db.Close(); 

事务处理

  1. void BeginTransaction();  
  2. void CommitTransaction();  
  3. void RollbackTransaction(); 

但是当前版本还没有事务支持。

查询操作

其实这么多操作之中查询操作的实现是最复杂的。

  1. int     ExecuteReader(const CString& sql); 

执行ExecuteReader()会根据select语句初始化一个结果集,和ADO.net的实现不一样,这个结果集不是直接通过DataSet或者DataReader来返回的,而是保持在内部的IRowset的结构里面。为了方便使用,SqlCeHelper实现了一个只读,向前的数据读取方法。

  1. bool IsEndOfRecordSet();void MoveNext();  
  2. void CloseReader();  
  3. int        GetRowInt(const long ordinal);  
  4. double    GetRowDouble(const long ordinal);  
  5. CString    GetRowStr(const long ordinal); 

当调用ExecuteReader()后,可以调用IsEndOfRecordSet()判断结果集是否为空。MoveNext()为移动到下一条记录。GetRowInt(), GetRowDouble()和 GetRowStr()为读取当前记录的数据。CloseReader()关闭结果集。

  1. SqlCeHelper db;      
  2. HRESULT hr = db.Open(DB_FILE_NAME);    
  3.   if(hr < 0)    {      
  4.     CString cstr = db.GetErrorsMessage();       
  5.    char* str = new char[cstr.GetLength()+1];        sprintf(str, "%S", cstr);     
  6.      FAIL(str);      
  7.     delete str;     
  8.  }        
  9.   CString sqlStr;      
  10. sqlStr.Format(L"SELECT * FROM T1");     
  11.  hr = db.ExecuteReader(sqlStr);      
  12. if(hr < 0)    {         
  13.  CString cstr = db.GetErrorsMessage();       
  14.    char* str = new char[cstr.GetLength()+1];        sprintf(str, "%S", cstr);       
  15.    FAIL(str);       
  16.    delete str;     
  17.  }          
  18. while(!db.IsEndOfRecordSet())     
  19.  {         
  20.  wprintf(L"F1=[%d], F2=[%s], F3=[%s]\n", db.GetRowInt(1), db.GetRowStr(2), db.GetRowStr(3));     
  21.      db.MoveNext();   
  22.    }      
  23. db.CloseReader();    
  24.   db.Close(); 

上面演示整个读取过程。

Unit Test

项目开发中使用了TDD,关于Unit Test可以参考Wince和Windows Mobile下native C++的单元测试 和 Windows Mobile下使用CppUnitLite输出测试结果 。

TO-DO-LIST

**Support to open the database with password

**Support to specify the Open Mode

**Support to load Ole Db without COM registry.

**Support Transactions

**Support Parameters

原文标题:Windows Mobile下Native C++访问SqlCe的封装

链接:http://www.cnblogs.com/procoder/archive/2009/09/09/1562947.html

【编辑推荐】

  1. C++之运算符重载,输入输出流详细介绍
  2. C++、Java与C#的命名规范总结
  3. C++类成员函数的重载、覆盖与隐藏
  4. Eclipse下C/C++环境搭建
  5. Java与C++语言在作用域上的差异浅析
责任编辑:彭凡 来源: 博客园

同话题下的热门内容

大反转,iOS15.6比iOS14.8优化更好,续航提升很满意,推荐升级佩洛西窜台,苹果躺枪?iPhone14或延迟发布抖音 iOS 推荐 Feed 容器化总结携程小程序生态之Taro跨端解决方案注意!iOS 15.4.1 还剩余 七 天,你会选择升级吗?iOS16新测试版发布,消失5年的功能回归马化腾:为什么你们不在乎QQ等级,不用QQ了吗?使用 Swift Package 插件生成代码

编辑推荐

2017年9月编程语言排行榜:Java、C与C++三巨头还能统治排行榜多久?初学者最容易学的六种编程语言CVPR 2017论文解读:特征金字塔网络FPN手把手教你搭建PHP版RabbitMQ消息队列开发环境及Demo实践微信小程序“反编译”实战(一):解包
我收藏的内容
点赞
收藏

51CTO技术栈公众号