创建一个基于模板的数据库记录集操作类(二)

创建一个基于模板的数据库记录集操作类(二)
       上一篇讲到了根据一个typelist实现一个结构,这个结构带有typelist中所有类型的成员,同时,可以通过Field0,Field1等接口访问和赋值.在这个基础上,我们可以构建对应一条记录的结构data_row,

二.一条记录

#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生成需要的类,而这里是用模板生成的.

三.数据类型转换
      数据库中的表对应的字段有不同的数据类型,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 ;
    }
}

上面的模板函数的功能是从_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;



上面的代码预定义了几种常用的数据类型,这个数据的封装类支持 = 操作符,因此可以直接用被封装的数据对其赋值.象下面
int  i  =   4 ;
DB_INT di;
di 
=  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自动转换,但是需要在上一层的记录集类中加入相关的转换操作,实现起来比较麻烦,所以我这里选择了对数据进行封装.


 

你可能感兴趣的:(创建一个基于模板的数据库记录集操作类(二))