创建一个基于模板的数据库记录集操作类(二)
上一篇讲到了根据一个typelist实现一个结构,这个结构带有typelist中所有类型的成员,同时,可以通过Field0,Field1等接口访问和赋值.在这个基础上,我们可以构建对应一条记录的结构data_row,
二.一条记录
三.数据类型转换
数据库中的表对应的字段有不同的数据类型,ADO操作接口中用不同的数据类型与之对应,其中Field接口的GetType就是返回字段类型的,但是ADO的GetValue返回的是_variant_t类型,为了实际业务的需要,还需要转换成不同的类型,因此,需要对_variant_t类型进行转换.为此需要提供模板转换函数
上面的模板函数的功能是从_variant_t转换到某中数据类型,对于其它类型还可以进行扩充,对于没有进行特化的函数,编译器会使用缺省模板,在运行时候就会出现提示.有了上面的函数,现在我们需要一个数据类型的封装类,使得被封装的类型可以自动进行从_variant_t类型的需要类型的转换,所以有了下面的封装类.
上面的代码预定义了几种常用的数据类型,这个数据的封装类支持 = 操作符,因此可以直接用被封装的数据对其赋值.象下面
二.一条记录
#define ROW_NO_CHANGE
0
#define ROW_ADD 1
#define ROW_UPDATE 2
#define ROW_DELETE 3
template < typename _tlist >
class data_op_record_row : public struct_mem < _tlist >
{
public :
enum _enum_RowState {
_en_Row_NoChange = ROW_NO_CHANGE, // 未修改
_en_Row_Add = ROW_ADD, // 新增记录
_en_Row_Update = ROW_UPDATE, // 更新
_en_Row_Del = ROW_DELETE, // 删除
} m_en_State;
public :
void SetState( int newstate) {
if (m_en_State ! = newstate) {
if (newstate == _en_Row_NoChange ||
newstate == _en_Row_Add ||
newstate == _en_Row_Update ||
newstate == _en_Row_Del)
{
m_en_State = (_enum_RowState)newstate;
}
}
}
public :
data_op_record_row () : m_en_State(_en_Row_NoChange) {}
~data_op_record_row (){}
protected:
private :
};
上面的类增加了一个枚举,标识这条记录当前的状态,在记录集中,将根据记录的状态进行相关的操作.这个其实类似与.net中的DataRow,不过.net中的DataRow可以用wizzard生成需要的类,而这里是用模板生成的.
#define ROW_ADD 1
#define ROW_UPDATE 2
#define ROW_DELETE 3
template < typename _tlist >
class data_op_record_row : public struct_mem < _tlist >
{
public :
enum _enum_RowState {
_en_Row_NoChange = ROW_NO_CHANGE, // 未修改
_en_Row_Add = ROW_ADD, // 新增记录
_en_Row_Update = ROW_UPDATE, // 更新
_en_Row_Del = ROW_DELETE, // 删除
} m_en_State;
public :
void SetState( int newstate) {
if (m_en_State ! = newstate) {
if (newstate == _en_Row_NoChange ||
newstate == _en_Row_Add ||
newstate == _en_Row_Update ||
newstate == _en_Row_Del)
{
m_en_State = (_enum_RowState)newstate;
}
}
}
public :
data_op_record_row () : m_en_State(_en_Row_NoChange) {}
~data_op_record_row (){}
protected:
private :
};
三.数据类型转换
数据库中的表对应的字段有不同的数据类型,ADO操作接口中用不同的数据类型与之对应,其中Field接口的GetType就是返回字段类型的,但是ADO的GetValue返回的是_variant_t类型,为了实际业务的需要,还需要转换成不同的类型,因此,需要对_variant_t类型进行转换.为此需要提供模板转换函数
template
<
typename
_type
>
void DbData_Change(_type & ret, _variant_t & field)
{
AfxMessageBox( " 未定义的数据转换 " );
}
template <>
void DbData_Change < int > ( int & ret, _variant_t & field)
{
ret = field.lVal;
}
template <>
void DbData_Change < std:: string > (std:: string & ret, _variant_t & field)
{
_bstr_t temp;
if (field.vt ! = VT_NULL) {
temp = field.bstrVal;
ret = temp.operator const char * ();
}
}
template <>
void DbData_Change < bool > (bool & ret, _variant_t & field)
{
ret = (field.boolVal == (short)0xFFFF ? TRUE : FALSE );
}
template <>
void DbData_Change < double > ( double & ret, _variant_t & field)
{
if (field.vt ! = VT_NULL) {
// ret = field.cyVal;
ret = field.dblVal;
} else {
ret = 0 ;
}
}
void DbData_Change(_type & ret, _variant_t & field)
{
AfxMessageBox( " 未定义的数据转换 " );
}
template <>
void DbData_Change < int > ( int & ret, _variant_t & field)
{
ret = field.lVal;
}
template <>
void DbData_Change < std:: string > (std:: string & ret, _variant_t & field)
{
_bstr_t temp;
if (field.vt ! = VT_NULL) {
temp = field.bstrVal;
ret = temp.operator const char * ();
}
}
template <>
void DbData_Change < bool > (bool & ret, _variant_t & field)
{
ret = (field.boolVal == (short)0xFFFF ? TRUE : FALSE );
}
template <>
void DbData_Change < double > ( double & ret, _variant_t & field)
{
if (field.vt ! = VT_NULL) {
// ret = field.cyVal;
ret = field.dblVal;
} else {
ret = 0 ;
}
}
上面的模板函数的功能是从_variant_t转换到某中数据类型,对于其它类型还可以进行扩充,对于没有进行特化的函数,编译器会使用缺省模板,在运行时候就会出现提示.有了上面的函数,现在我们需要一个数据类型的封装类,使得被封装的类型可以自动进行从_variant_t类型的需要类型的转换,所以有了下面的封装类.
//
数据库数据类型封装
template < typename _type >
class _db_data_wrapper
{
public :
_type & Value() {
return m_Data;
}
const _type & operator = ( const _type & value) {
m_Data = value;
return value;
}
_db_data_wrapper & operator = ( const _db_data_wrapper & other) {
if (this ! = & other) {
m_Data = other.m_Data;
}
return * this;
}
public :
virtual void GetDbValue(_variant_t & field_value) {
DbData_Change(m_Data, field_value);
}
public :
_db_data_wrapper(){}
_db_data_wrapper( const _type & value) : m_Data(value) {}
~_db_data_wrapper(){}
private :
_type m_Data;
};
typedef _db_data_wrapper < int > DB_INT;
typedef _db_data_wrapper < std:: string > DB_STRING;
typedef _db_data_wrapper < bool > DB_BOOL;
typedef _db_data_wrapper < double > DB_DOUBLE;
template < typename _type >
class _db_data_wrapper
{
public :
_type & Value() {
return m_Data;
}
const _type & operator = ( const _type & value) {
m_Data = value;
return value;
}
_db_data_wrapper & operator = ( const _db_data_wrapper & other) {
if (this ! = & other) {
m_Data = other.m_Data;
}
return * this;
}
public :
virtual void GetDbValue(_variant_t & field_value) {
DbData_Change(m_Data, field_value);
}
public :
_db_data_wrapper(){}
_db_data_wrapper( const _type & value) : m_Data(value) {}
~_db_data_wrapper(){}
private :
_type m_Data;
};
typedef _db_data_wrapper < int > DB_INT;
typedef _db_data_wrapper < std:: string > DB_STRING;
typedef _db_data_wrapper < bool > DB_BOOL;
typedef _db_data_wrapper < double > DB_DOUBLE;
上面的代码预定义了几种常用的数据类型,这个数据的封装类支持 = 操作符,因此可以直接用被封装的数据对其赋值.象下面
int
i
=
4
;
DB_INT di;
di = i;
i = di.Value();
DB_INT di;
di = i;
i = di.Value();
同时通过成员函数GetDbValue(_variant_t& field_value), 支持从_variant_t转换为自身封装的类型.
现在,可以用上面的数据类型构建记录结构了
typedef data_op_record_row< TYPELIST_2(DB_INT,DB_STRING) > my_DataRow;
在上面的my_DataRow类型中,有两个成员Field0, Field1,类型分别为 DB_INT,DB_STRING, 支持_variant_t类型转换.
当然,用wrapper对数据进行封装在实际的使用中毕竟有些麻烦, 如数据必须通过 Value() 函数来取得,如果直接使用象 int, std::string 等类型作为 记录结构的成员,也可以实现_variant自动转换,但是需要在上一层的记录集类中加入相关的转换操作,实现起来比较麻烦,所以我这里选择了对数据进行封装.