英创公司
2009-7-7
在软件编程中,数据库始终是很重要的一部分。通过数据库,可以非常方便地存储和检索数据,极大地提高工作效率。如果我们需要存储的数据量较小,数据结构相对简单,例如个人通讯簿,则使用WinCE自带的数据库是非常合适的。如表一所示,列出了WinCE自带数据库与SQLCE数据库部分功能的对比,用户可以根据自己的需要,选择合适的数据库。关于WinCE自带数据库的操作请参考《EVC高级编程及其应用开发》WinCE基础数据库编程部分。本文主要讲解在eVC开发环境下,以使用ADOCE 3.1为例详细说明开发SQLCE本地数据库的方法。
表一:WinCE自带数据库与SQLCE数据库功能对照表
|
WinCE自带数据库 |
SQLCE数据库 |
开发方式 |
使用API函数操作 |
使用SQL语句操作 |
数据类型 |
较少(9种) |
较多(20种) |
与pc端SQL Sever数据同步 |
不支持 |
支持 |
更改表字段 |
不支持 |
支持 |
ADOCE(Active Data Object for Windows CE)技术提供了高层数据库应用软件的访问接口,可在eVC、eVB等高级语言环境中直接使用,ADOCE是一种易用的COM组件,关于COM组件的开发与调用在《ARM9工控板在远程监控中的应用》系列文章中有详细的说明。ADOCE作为开发WinCE数据库应用程度的面向对象的COM接口,其访问数据库是通过访问OLE DB数据提供程序来进行的,并且提供了一种对OLEDB数据提供程序的简单高层访问接口。ADOCE技术简化了OLE DB的操作,在OLE DB的程序中使用了大量的COM接口,而ADOCE则封装了这些接口,所以,ADOCE是一种高层的访问技术。ADOCE的数据存储模型如图1 所示:
图1 ADOCE的数据存储模型
ADOCE支持Connection、Recordset、Field、Fields、Error对象,但不支持Command对象、Property对象以及Properties collection。下面介绍几个重要的ADOCE对象。
连接对象(Connection)
Connection对象建立一个对象数据源的数据交换环境,ADOCE允许建立对ACCESS数据源和SQLCE数据源的连接。
记录集对象(Recordset)
Recordset对象是ADOCE数据操作的核心,它是查询结果的集合,可以通过这个结果集处理来自数据源的数据,包括修改记录、更新记录、插入和删除记录等。可以通过Recordset的Open方法执行SQL语句,实现数据库的操作。
字段对象(Field)
字段对象的每条记录都由Fields组成,其中包括名称、数据和值。
基于ADOCE的WinCE数据库开发程序包括以下基本步骤:
l 创建Connection对象
l 打开数据源,建立同数据源的连接
l 创建Record对象
l 将Recordset的连接字符串设置到Connection对象中
l 使用SQL命令
l 通过Recordset对象完成结果记录集的操作
l 终止连接
SQL是Structure Query Language结构化查询语言的缩写,通过SQL语句的执行,可以对数据库内容(表及记录)进行修改或查询,因此数据库的操作就是执行SQL语句。下面简要介绍下几个重要的SQL语句。
1、Create Table语句功能是创建表,其语法格式如下:
Create Table 表名称 (字段名称 数据类型 [(字段长度)] [,字段名称 数据类型 [(字段长度)] ,[ PRIMARY KEY | UNIQUE ] ]
例如: CREATE TABLE Products (ProductID int,Name nvarchar(255), PRIMARY KEY (ProductID)
2、Drop Table语句的功能是将一个现存于数据库内的表删除,其所使用的语法与格式如下所示:
Drop Table 表名称
3、Select语句可以对表的记录作查询、统计。由于Select语句使用比较灵活,我们以几个具体的例子讲价Select的用法。
Select 字段名称 [,字段名称] From 表名称
其中,From关键词是设置来源表名称,使用时可以设置使用一个或多个表,而表名称间以逗号分隔。在搜寻结果中取出所需的字段内容,设置的字段名称以逗号分隔,如果要取得表上的所有字段,可直接用“*”表示。
SELECT * FROM Products WHERE ProductID='02'
Where关键词是设置查询记录条件,用以取得所有符合设置条件内容的记录。在条件设置中可以使用 > 、<、=等比较符号,而对于多项条件的判断也可以利用AND,OR等逻辑操作数来连接。
4、插入记录
INSERT INTO 表名[(field1[, field2[, ...]])] VALUES (value1[, value2[, ...]]
例如:INSERT INTO Products (ProductID,Name) VALUES (1,'EM9000嵌入式模块')
5、删除记录
DELETE FROM 表名 WHERE criteria
例如:DELETE FROM 表名 WHERE ProdutcID=01
6、更新记录
UPDATE 表名 SET newvalue WHERE criteria;
例如:Update Products set Name=’EM9161嵌入式主板’ where ProdcutID=01
在eVC环境下,对数据的开发,其实就是通过ADOCE COM组件执行SQL语句的过程。为了使用户方便的使用ADOCE,我们提供了DBManager类,通过此类,可以方便的建立与数据库的连接、执行sql语句等操作。
在EVC环境下由于没有提供专门的API函数对SQLCE进行操作,这就需要通过上面介绍的ADOCE组件来实现这一功能。为了方便用户使用SQLCE数据库,利用ADOCE组件技术,针对数据库操作中常用的功能,包括创打开数据库、建数据表等,英创提供了一个对SQLCE数据库操作的管理类DBManager,应用程序通过调用该类中提供的API函数,就可以很方便的建立与SQLCE的链接、打开数据库,并可以直接利用SQL语句来对数据库进行建立表、为表添加记录以及查询表中的记录等功能。在eVC环境下通过DBManager类访问SQLCE数据库模型如图2所示。
图2 EVC通过DBManager访问数据库模型
DBManager类主要提供打开数据库、执行SQL语句、移动记录指针等方法。其头文件声明如下:
//函数功能:打开数据库
//入口参数:lpszFileName表示要打开的数据库名称,为绝对路径加文件名。
//出口参数:无
//返回值:TRUE:打开数据库成功;FALSE:打开数据库失败
bool OpenDatabase(LPCTSTR lpszDBName);
//函数功能:执行SQL语句
//入口参数:lpstrSql为要执行SQL语句的字符串。
//出口参数:无
//返回值:TRUE:执行SQL语句成功;FALSE:执行SQL语句失败
bool ExecSql(LPCTSTR lpstrSql);
//函数功能:是否是记录的开始
//入口参数:无
//出口参数:无
//返回值:TRUE:是记录的开始;FALSE:不是记录的开始
bool IsBOF();
//函数功能:是否是记录的末尾
//入口参数:无
//出口参数:无
//返回值:TRUE:是记录的末尾;FALSE:不是记录的末尾
bool IsEOF();
//函数功能:移动到首记录
//入口参数:无
//出口参数:无
//返回值:TRUE:执行成功;FALSE:执行失败
bool MoveFirst(); //移到首记录
//函数功能:下移一条记录
//入口参数:无
//出口参数:无
//返回值:TRUE:执行成功;FALSE:执行失败
bool MoveNext(); //下移一个记录
//函数功能:取得数据 iField为字段顺序
//入口参数:iField,要得到字段序号,注意,字段序号从0开始。
//出口参数:无
//返回值:数据 iField为字段顺序的值,注意值为VARIANT类型
VARIANT GetFieldValue(int iField); //取得数据 iField为字段顺序
使用DBManager类完成对数据库的基本操作,方法如下:
首先打开数据库,注意,参数为数据所在的绝对路径,例如,打开nandflash目录下的emtronix.sdf数据库:
DBManager dbm; //定义一个DBManager对象
CString filename=_T("//NandFlash//emtronix.sdf"); //要打开的数据库名
dbm.OpenDatabase(filename) //打开数据库
打开数据库后,就可以执行相应的SQL语句,对数据库中的数据进行相应的操作。下面仅以几个典型的SQL语句说明使用DBManager类实现对数据库的操作。
l 在数据库中创建一个新表。使用SQL语句在数据库中创建一个名为Products的数据表,用于保存英创公司产品信息,该表包含五个字段,实现方法如下
execsql=("CREATE TABLE Products (编号 int,产品名称 nvarchar(40),CPU型号 nvarchar(40),RAM nvarchar(20),Flash nvarchar(20))");
dbm.ExecSql(execsql);
l 删除数据库指定名称的数据表,例如,删除Products表,方法如下:
execsql=("DROP TABLE Products");
dbm.ExecSql(execsql);
l 在数据表中插入记录,例如,插入英创公司EM9000产品信息到Products表中
execsql=_T("INSERT INTO Products (编号, CPU型号,产品名称, RAM,Flash) VALUES (1, 'ARM9 CL EP9315','EM9000嵌入式模块', '64MB','32MB')");
dbm.ExecSql(execsql);
注意,Products为表名,(编号,产品名称,CPU型号,RAM,Flash)为表的字段名,字段名的顺序可以和表中的字段顺序不一致,但是,VALUES中的值的顺序必须和此字段一致。字段名也可以省略,省略后,VALUES中的值,顺序必须和表中字段的顺序一致。例如,省略字段名后,也可以使用以下操作。
execsql=_T("INSERT INTO Products VALUES (1, 'EM9000嵌入式模块''ARM9 CL EP9315',, '64MB','32MB')");
dbm.ExecSql(execsql);
l 在表中选取符合指定条件的记录。使用Select语句,可以选取符合指定条件的记录,选取后的记录由Recordset对象管理,使用MoveNext、MoveFirst等方法可以在记录间移动。例如,选取“产品名称”为EM9000的记录,方法如下:
execsql="SELECT * FROM Products where 产品名称=’EM9000’";
dbm.ExecSql(execsql);
l 得到记录的字段值。选取到记录后,我们关心的是,得到记录的字段数据。DBManager类提供了得到记录字段的函数,其参数为字段的顺序号,注意,此顺序号是从0开始的。例如,得到记录的“编号”值,注意,GetFieldValue函数的返回值为Variant。
int ProcutID;
vValue = dbm.GetFieldValue(0);
ProcutID = vValue.iVal;
下面详细说明使用DBManager类操作数据库。
1、 使用DBManager类操作数据库的详细过程如下:创建一个WCE Application工程,取名为SqlTest。
图3 新建EVC工程
2、 选择A simple Windows CE application,点击Finish完成工程。
图4 新建EVC工程向导
3、 把adoce31.h、adocec31.h 、DBManager.h和DBManager.cpp拷贝到当前工程目录中,并添加到eVC工程中。如下图5所示。
图5 EVC开发环境
4、 在sqltest.cpp中,包含DBManager.h,为了使用CSring类,包含Afx.h,为了使用wprintf输出汉字,包含stdio.h文件。
5、 在主函数中,调用DBManager类的函数顺序如下:
l 打开数据库
l 执行SQL语句,完成创建表、插入记录、更新记录、查询记录等操作。
以下是详细的C代码。
VariantInit(&vValue); //查询记录的返回值
CString filename=_T("//NandFlash//emtronix.sdf"); //要打开的数据库名
dbm.OpenDatabase(filename) //打开数据库
CString execsql;
//演示新建表 删除表插入字段读出字段
execsql="CREATE TABLE Products (ProductID int,Name nvarchar(60),CPUType nvarchar(40),RAM nvarchar(20),Flash nvarchar(20))"; //创建表
dbm.ExecSql(execsql);
execsql="INSERT INTO Products (ProductID,Name,CPUType,RAM,Flash) VALUES (1,'EM9000嵌入式模块','ARM9 CL EP9315','64MB','32MB')";//插入记录
dbm.ExecSql(execsql);
execsql="SELECT * FROM Products"; //查询products表中的所有记录
dbm.ExecSql(execsql);
dbm.MoveFirst(); //移动到第1条记录
while (!dbm.IsEOF()) //显示所有记录
{
vValue = dbm.GetFieldValue(0); //得到第0个字段的值
ProductID = vValue.iVal;
wprintf(L"%d ", ProductID);
vValue = dbm.GetFieldValue(1); //得到第1个字段的值
dbname = vValue.bstrVal; //必须知道数据库字段的数据类型
wprintf(L"%s ",dbname);
dbm.MoveNext(); //移动到下一条记录
}
6、 由于ADOCE的参数都为Vareant类型,所以在link标签连接Ole32.lib和Oleaut32.lib
图6 设置Link选项卡
7、 在Debug模式下调试运行,会在eVC的debug窗口和调试串口输出数据库的信息。
DBManager类的使用环境是EVC,为了使用户更好的理解使用ADOCE COM组件进行数据库操作,下面对DBManager类进行解释。
1、 在DBManager.h文件中添加ADO的某些常量定义。代码如下:
namespace MSADOCE { #include "adoce31.h" } //应把adoce31.h复制到当前工程目录
//定义连接对象唯一标识
const IID IID__Connection = {0x113033DE,0xF682,0x11D2,{0xBB,0x62,0x00,0xC0,0x4F,0x68,0x0A,0xCC}};
//定义记录对象唯一标识
const IID IID__Recordset = {0x113033F6,0xF682,0x11D2,{0xBB,0x62,0x00,0xC0,0x4F,0x68,0x0A,0xCC}};
//定义连接对象字符串名
const TCHAR g_szADOCE31ConnProgID[]= TEXT("ADOCE.Connection.3.1");
//定义记录对象字符串名
const TCHAR g_szADOCE31RSProgID[]= TEXT("ADOCE.Recordset.3.1");
2、 为DBManager类添加私有成员变量,用于定义ADO连接对象、记录集对象、字段集对象和字段对象,定义如下:
private:
MSADOCE::IADOCEConnection *m_pADOCEConn ; //连接对象
MSADOCE::IADOCERecordset *m_pADOCERS ; //记录集对象
MSADOCE::IADOCEFields *m_pADOCEFields ; //字段集对象
MSADOCE::IADOCEField *m_pADOCEField ; //字段对象
bool m_bIsOpen; //打开数据库标志
3、 实现CreateConnection函数。建立与SQLCE数据源连接共需要五个步骤。
bool DBManager::CreateConnection()
{
CLSID tClsid;
HRESULT hr;
//初始化COM库
CoInitializeEx(NULL,COINIT_MULTITHREADED);
//1,得到ADO连接对象对应ClassID
hr = CLSIDFromProgID( g_szADOCE31ConnProgID, &tClsid );
//2,创建ADO连接对象
hr = CoCreateInstance (tClsid, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
IID__Connection, (LPVOID *)&m_pADOCEConn);
//3.设置连接数据库的Provider
hr = m_pADOCEConn->put_Provider(TEXT("CEDB"));
//4.得到记录集对象的ClassID
hr = CLSIDFromProgID( g_szADOCE31RSProgID, &tClsid );
//5.创建结果集对象
hr = CoCreateInstance (tClsid, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
IID__Recordset,(LPVOID *)&m_pADOCERS);
}
4、 实现OpenDatabase函数,打开数据库。打开数据库,其实就是执行Connection对象的Open函数,然后设置Recordset对象到已建立的连接上。
bool DBManager::OpenDatabase(LPCTSTR szDbName)
{
HRESULT hr;
VARIANT varConn1;
TCHAR buf[200]=_T("Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0; data source =");
wcscat(buf,szDbName);
//执行Connection对象的Open函数
hr=m_pADOCEConn->Open(buf,TEXT(""), TEXT(""),MSADOCE::adOpenUnspecified );
VariantInit(&varConn1);
varConn1.pdispVal=m_pADOCEConn;
varConn1.vt=VT_DISPATCH;
//设置结果集对象到已建立的连接上。注意参数是Variant类型
hr=m_pADOCERS->put_ActiveConnection(varConn1);
}
5、 其它函数见光盘提供的源码。
本示例程序完成了数据库的基本操作,如果你需要通过WebServer操作数据库请关注本公司的后续文章。