c++在数据库开发这种需要进行快速开发的地方一直是以效率低下著称,borland 的c++ build 依赖vcl提供的组件勉强可以实现,但是由于用的是pascal的东西,根基不行,一直叫不响.再看看现在流行的数据库,sql server 和mysql 等虽然提供本地开发的头文件和库,但是对于一些可能使用不同数据库的应用来说,选择特定某种数据库开发显然是不妥,因此,象ado这种数据操作接口大行其道.这又给用c++开发带来了麻烦,象vb等工具可以自动转换variant类型,但是在vc使用的时候却很麻烦.网上那些使用ado接口的c++的例子,大多数都从#import 那个dll开始, 然后就是繁琐的创建instance,打开记录集,最后还要进行一个variant到c++类型的转换,确实是够麻烦的,难怪效率低下.
在很多情况下,一些数据查询和数据操作往往是在开发的时候就确定下来了,比如说你有个用户表要操作,你在开发的时候就知道这个表中的所有字段名称和字段类型,但是你用ado,你却还是要和繁琐的variant打交道,把它转换为你想要的数据类型. 如果能实现一个类,在知晓数据表字段类型的情况下,可以方便地使用c++数据类型,并且可以进行诸如插入,删除,更新等操作,那就方便多了. 这就是本文想实现的目标. 但是对于那些在运行时候才确定的数据操作,如用户输入一个 sql 查询,然后再来进行操作,对于象c++ 这种强类型的语言来说,可能除了使用 variant别无他法, 对于这方面,本文没有给出解决办法.
本文中的代码在vc6下编译通过
需要的库 loki for vc6, boost
一. 构造记录结构
通常来说,数据集由一条条的记录组成,记录下有字段,记录是数据操作的基本单元.照c++的习惯,最好是一条记录一个结构,字段就是这个结构的成员,然后用列表或者vector组合一下就是记录集了.但是一条记录的字段是有可能变动的,还好,有loki 的 typelist.
1 #if !defined(INCLUDE_40697E96_B6DE_449D_A516_B0376650A488)
2 #define INCLUDE_40697E96_B6DE_449D_A516_B0376650A488
3
4 #if _MSC_VER > 1000
5 #pragma once
6 #endif
7
8 #include <typelist.h>
9 #include <functor.h>
10 #include <boost/preprocessor/dec.hpp>
11
12 #define HELP_2(a , b) a(b)
13
14 #define MEM_STRUCT_MAKE_IMPL(n) template <typename _tlist> \
15 struct In : public _str_impl_help<n>::template In<typename _tlist::Tail> \
16 { \
17 typedef _str_impl_help<n>::template In<typename _tlist::Tail> _Base; \
18 enum { en_member_count = _Base::en_member_count+1, }; \
19 typedef typename ::Loki::TL::TypeAt<_tlist, 0>::Result _type##n; \
20 _type##n m_P##n; \
21 __declspec(property(get = GetF##n, put = PutF##n)) \
22 _type##n Field##n; \
23 _type##n GetF##n() { return m_P##n; } \
24 void PutF##n(const _type##n val) { m_P##n = val; } \
25 }; \
26 }
27
28 #define MEM_STRUCT_MAKE(n) template <> \
29 struct _str_impl_help<n> { \
30 HELP_2(MEM_STRUCT_MAKE_IMPL, BOOST_PP_DEC(n))
31
32
33 namespace impl_help
34 {
35 template <int _p>
36 struct _str_impl_help;
37
38 template <>
39 struct _str_impl_help<0> {};
40 template <>
41 struct _str_impl_help<1> {
42 template <typename _tlist>
43 struct In {
44 enum {
45 en_member_count = 1,
46 };
47
48 typename ::Loki::TL::TypeAt<_tlist, 0>::Result m_P0;
49
50 __declspec(property(get=GetF0, put=PutF0))
51 typename ::Loki::TL::TypeAt<_tlist, 0>::Result Field0;
52
53 typename ::Loki::TL::TypeAt<_tlist, 0>::Result GetF0() {
54 return m_P0;
55 }
56
57 void PutF0(const typename ::Loki::TL::TypeAt<_tlist, 0>::Result val) {
58 m_P0 = val;
59 }
60 };
61 };
62
63 MEM_STRUCT_MAKE(2);
64 MEM_STRUCT_MAKE(3);
65 MEM_STRUCT_MAKE(4);
66 MEM_STRUCT_MAKE(5);
67 MEM_STRUCT_MAKE(6);
68 MEM_STRUCT_MAKE(7);
69 MEM_STRUCT_MAKE(8);
70 MEM_STRUCT_MAKE(9);
71 MEM_STRUCT_MAKE(10);
72 MEM_STRUCT_MAKE(11);
73 MEM_STRUCT_MAKE(12);
74 MEM_STRUCT_MAKE(13);
75 MEM_STRUCT_MAKE(14);
76 MEM_STRUCT_MAKE(15);
77 }
78
79 template <typename _tlist>
80 struct struct_mem : public impl_help::_str_impl_help< ::Loki::TL::Length<_tlist>::value >::
81 template In< ::Loki::TL::Reverse<_tlist>::Result >
82 {
83 };
84
85
86 #endif //!defined(INCLUDE_40697E96_B6DE_449d_A516_B0376650A488)
上面是模板实现根据指定typelist,生成拥有相应成员的结构.
typedef struct_mem< TYPELIST_6(DB_STRING, DB_STRING, DB_STRING, DB_STRING, DB_STRING, DB_STRING) > CustomerRow; 就可以声明一个有6个成员的结构了.
上面的代码使用template的特化到有15个成员的结构,全部写出来的话,重复而且麻烦,所以使用了宏来帮助生成.