OLEDB 静态绑定和数据转化接口
OLEDB 提供了静态绑定和动态绑定两种方式,相比动态绑定来说,静态绑定在使用上更加简单,而在灵活性上不如动态绑定,动态绑定在前面已经介绍过了,本文主要介绍OLEDB中的静态,以及常用的数据类型转化接口。
静态绑定
之前的例子都是根据返回的COLUMNINFO结构来知晓数据表中各项的具体信息,然后进行绑定操作,这个操作由于可以动态的针对不同的数据类型绑定为不同的类型,因此称之为动态绑定。动态绑定是建立在我们对数据库中表结构一无所知,而又需要对数据库进行编程,但是一般在实际的项目中开发人员都是知道数据库的具体结构的,而且一旦数据库设计好了后续更改的可能性也不太大,因此可以采取静态绑定的方式来减少编程的复杂度。
在进行静态绑定时,一般针对每个数据库表结构定义一个结构体用来描述表的各项数据,然后利用结构体的偏移来绑定到数据库中。
数据关系对应表
一般静态绑定需要将数据库表的各项数据与结构体中的成员一一对应,这个时候就涉及到数据库数据类型到C/C++中数据类型的转化,下表列举了常见的数据库类型到C/C++数据类型的转化关系
| 数据库类型 | OLEDB 类型 | C/C++类型 |
|---|---|---|
| binary | DBTYPE_BYTES/DBTYPE_IUNKNOWN | BYTE[length]/BLOB |
| varbinary | DBTYPE_BYTES/DBTYPE_IUNKNOWN | BLOB |
| bit | DBTYPE_BOOL | VARIANT_BOOL |
| char | DBTYPE_STR | char[length] |
| varchar | DBTYPE_STR | char[length] |
| nvarchar | DBTYPE_WSTR | wchar_t[length] |
| nchar | DBTYPE_WSTR | wchar_t[length] |
| text | DBTYPE_STR/DBTYPE_IUNKNOWN | BLOB |
| image | DBTYPE_BYTES/DBTYPE_IUNKNOWN | BLOB |
| ntext | DBTYPE_WSTR/DBTYPE_IUNKNOWN | BLOB |
| tinyint | DBTYPE_UI1 | BYTE |
| smallint | DBTYPE_I2 | SHORT |
| int | DBTYPE_I4 | LONG |
| bigint | DBTYPE_I8 | LARGE_INTEGER |
| real | DBTYPE_R4 | float |
| float | DBTYPE_R8 | double |
| money | DBTYPE_CY | LARGE_INTEGER |
| numeric | DBTYPE_NUMERIC | typedef struct tagDB_NUMERIC { BYTE precision; BYTE scale; BYTE sign; BYTE val[16]; } DB_NUMERIC; |
| decimal | DBTYPE_NUMERIC | typedef struct tagDB_NUMERIC { BYTE precision; BYTE scale; BYTE sign; BYTE val[16]; } DB_NUMERIC; |
| sysname | DBTYPE_WSTR | wchar_t[length] |
| datetime | DBTYPE_DBTIMESTAMP | typedef struct tagDBTIMESTAMP { SHORT year; USHORT month; USHORT day; USHORT hour; USHORT minute; USHORT second; ULONG fraction; }DBTIMESTAMP; |
| timestamp | DBTYPE_BYTES | BYTE[length] |
| uniqueidentifier | DBTYPE_GUID | GUID |
实例
下面是一个静态绑定的例子
//静态绑定的结构
typedef struct _tag_DBSTRUCT
{
DBSTATUS dbCodeStatus;
ULONG uCodeLength;
int nCode;
DBSTATUS dbNameStatus;
ULONG uNameLength;
WCHAR szName[NAME_LENGTH];
}DBSTRUCT, *LPDBSTRUCT;
dbBindings[0].bPrecision = 0;
dbBindings[0].bScale = 0;
dbBindings[0].cbMaxLen = sizeof(int);
dbBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
dbBindings[0].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
dbBindings[0].iOrdinal = pdbColumnInfo[0].iOrdinal;
dbBindings[0].obStatus = offsetof(DBSTRUCT, dbCodeStatus);
dbBindings[0].obLength = offsetof(DBSTRUCT, uCodeLength);
dbBindings[0].obValue = offsetof(DBSTRUCT, nCode);
dbBindings[0].wType = DBTYPE_I4;
dbBindings[1].bPrecision = 0;
dbBindings[1].bScale = 0;
dbBindings[1].cbMaxLen = sizeof(WCHAR) * NAME_LENGTH;
dbBindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
dbBindings[1].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
dbBindings[1].iOrdinal = pdbColumnInfo[1].iOrdinal;
dbBindings[1].obStatus = offsetof(DBSTRUCT, dbNameStatus);
dbBindings[1].obLength = offsetof(DBSTRUCT, uNameLength);
dbBindings[1].obValue = offsetof(DBSTRUCT, szName);
dbBindings[1].wType = DBTYPE_WSTR;
hRes = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 2, dbBindings, 0, &hAccessor, NULL);
pdbStruct = (DBSTRUCT*)COM_ALLOC(sizeof(DBSTRUCT) * cRows);
while (TRUE)
{
hRes = pIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, cRows, &cRowsObtained, &prghRows);
if (hRes != S_OK && cRowsObtained == 0)
{
break;
}
ZeroMemory(pdbStruct, sizeof(DBSTRUCT) * cRows);
for (int i = 0; i < cRowsObtained; i++)
{
hRes = pIRowset->GetData(prghRows[i], hAccessor, &pdbStruct[i]);
if (!FAILED(hRes))
{
COM_PRINTF(_T("%012d\t%s\n"), pdbStruct[i].nCode, pdbStruct[i].szName);
}
}
pIRowset->ReleaseRows(cRowsObtained, prghRows, NULL, NULL, NULL);
}
我们针对之前的行政区表来进行演示,在这个表中我们只查询其中的两列数据,与之前的例子相似,针对每列定义3项数据,分别是状态,长度和真实的数据,在绑定的时候就不需要计算总体需要内存的大小,行内存大小就是结构体的大小,在绑定的时候我们结构体成员在结构体中的偏移作为返回数据时各项在缓冲中的偏移。而在访问数据时就需要自己计算偏移,直接使用结构体中的成员即可。
从上面的例子,我总结了静态绑定和动态绑定之间的差别:
- 其实从本质上将动态绑定和静态绑定没有区别,都是分配一段缓冲作为行集的缓冲,然后在使用的时候进行偏移的计算
- 静态绑定是利用我们提前知道数据库的结构,实现通过结构体来安排各项在缓冲中的偏移所占内存的大小。
- 动态绑定中所有成员的分配和所占内存大小都是根据COLUMNINFO结构事后动态分配的,需要自己计算偏移。
- 相比于动态绑定来说,静态绑定不需要获取数据库的各项的属性信息,不需要自己计算各项的偏移,相对比较简单,适用于事先知道数据库的表结构,使用相对固定,一旦数据库结构改变就需要改变代码
- 动态绑定可以适用于几乎任何情形,可扩展性强,几乎不需要考虑数据库表结构变更问题。代码灵活,但是需要自己计算偏移,自己分配管理内存,相对来说对程序员的功力要求更高一些。
数据类型转化
数据库中数据类型繁多,而对应到具体的编程语言上有不同的展示方式,具体的语言中对同一种数据库类型有不同的数据类型对应,甚至有的可能并没有什么类型可以直接对应,这就涉及到一个从数据库数据类型到具体编程语言数据类型之间进行转换的问题,针对这一问题OLEDB提供了一个接口——IDataConvert
一般情况下任何数据类型都可以转化为相应格式的字符串,而对应的字符串又可以反过来转化为数据库中相应的数据类型。当然一些特殊转换也是允许的,比如:整型数据间的转换,浮点数间的转换等。这也是使用这个数据转化接口的主要原则。
数据转换接口的使用
- 使用COM标准的方式创建IDataConver接口(调用CreateInstance函数传入CLSID_OLEDB_CONVERSIONLIBRARY创建一个IID_IDataConvert接口)
- 接着调用该接口的DataConvert方法可以进行数据转化
- 调用接口的CanConvert可以知道两种数据类型之间能否进行转化。
- 调用GetConversionSize可以知道源数据类型转化为指定类型时需要的缓冲大小。
实例
这个例子相对比较简单,就简单的在之前打印数据库数据中加了一句转化为字符串的操作,然后打印,就不在文中展示了,具体的例子见我放到码云中的代码片段
例子代码:
OLEDB 静态绑定和数据转化接口的更多相关文章
- [XML] XML格式【有道翻译】API 的数据转化输出
<?php header("content-type:text/html;charset=utf-8"); //echo "飞飞仔超级智障"; $cont ...
- Enterprise Solution 生成实体数据访问接口与实现类型 Code Smith 6.5 模板文件下载
数据库表定义为SalesOrder,用LLBL Gen Pro生成的实体定义是SalesOrderEntity,再用Code Smith生成的数据读写接口是ISalesOrderManager,最后是 ...
- Fast RCNN 训练自己数据集 (2修改数据读取接口)
Fast RCNN训练自己的数据集 (2修改读写接口) 转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ http ...
- xml格式的数据转化成数组
将得到的xml格式的数据转化成数组 <?php //构造xml $url = "http://api.map.baidu.com/telematics/v3/weather?locat ...
- c#数据绑定(3)——数据转化为信息
文/嶽永鹏 本文主要在数据绑定1和2中新增了DataSet对象,练习了如何在DataSet中添加表.关系和约束,同时本文也简要的介绍了如何将数据转化为信息. 目标界面: XAML代码: <Gri ...
- Dojo Data Store——统一数据访问接口
原文地址:http://www.infoq.com/cn/articles/wq-dojo-data-store 无论在传统的桌面应用还是在主流的互联网应用中,数据始终占据着软件应用中的核心地位.当下 ...
- 将数据转化成字符串时:用字符串的链接 还是 StringBuilder
/* 目的:将数据转化成字符串时:用字符串的链接 还是 StringBuilder呢? */ public class Test{ public static void main(String[] a ...
- 免费股票数据API接口
免费股票数据API接口提供沪深.香港.美国股市信息. 1.沪深股市 2.香港股市 3.美国股市 4.香港股市列表 5.美国股市列表 6.深圳股市列表 7.沪股列表 API文档:https://www. ...
- Yii框架AR对象数据转化为数组
demo函数作用:将AR对象数据转化为数组 局限:仅用于findAll的多维数组,find一维数组可以先转化为多维数组的一个元素在使用 function actionIndex() { $data = ...
随机推荐
- js 对象 浅拷贝 和 深拷贝
网上发现一个比较好的博客 阮一峰的感觉很不错推荐大家看看. http://www.ruanyifeng.com/blog/it/javascript/ 接下来看一下这两个拷贝方法 1.浅拷贝 拷贝就是 ...
- (STM32F4) 精準的Delay不透過Timer
從一個厲害的國外工程師看來的delay寫法,使用while loop會使用幾個指令去計算,可能會需要多少時間. while(variable--); 這行代碼執行一次預估會消耗MCU 4 clock ...
- shell-004:检测机器存活或者网络陡动情况!
如下图情况,我们监测的就是此数据,当大于50%了,我们就可以设置告警等! #!/bin/bash # 用ping检测一台机器的存活或者网络波动情况 # 检测机器的丢包率来检测网络波动情况!! n=`p ...
- springcloud微服务config的使用
首先需要建立一个server端: pom依赖中加入 <dependency> <groupId>org.springframework.cloud</groupId> ...
- 【转】intellij idea使用指南—— 导入Eclipse的Web项目
通常一个团队中可能有人用eclipse,有人用intelliJ,那么经常会出现需要导入别人用eclipse建好的web项目.而IntelliJ提供了多种项目类型的导入方式,其中就有eclipse. 在 ...
- 【算法笔记】B1024 科学计数法
1024 科学计数法 (20 分) 科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [+-][1-9].[0-9]+E[+-][0-9]+,即数字的整数部分只有 1 位, ...
- poj2718
一.题意:给定一串数字,数字没有重复,个数为2~10个.求这些数字分为两份,组合成的两个数的差最小是多少 二.思路:首先可以肯定的是,将这n个数平均分成两份,所得到的最小差一定在其某个组合当中.因此可 ...
- 多个git库的ssh配置
当拥有多个git服务器,而且都是用ssh认证方式时,需要在~/.ssh下的config文件做如下配置 如下:第一个为本地git库,第二个为github库,第三个为默认git库 Host 192.168 ...
- element-ui日期组件DatePicker设置日期选择范围Picker Options
element-UI提供了DatePicker日期选择器组件,可以让我们很方便的获取到日期,默认的选择是全部的日期都可以选择的,但是很多场景中我们要对日期选择范围做限定,比如出行日期就不能选过去的日期 ...
- PHP CURL_ERRNO 77
项目中碰到curl https偶尔出现false,错误码77,可以尝试下面两种解决方法: 1.确认安装机器ca-certificates,重启PHP.设置curl_setopt($ch, CURLOP ...