简单的数据库应用开发(续)

简单的数据库应用开发(续)

三、编写工程代码

10. 编写CMemberSystemView类的处理函数
CMemberSystemView类的处理函数在MemberSystemView.h文件里有如下的声明:
    private:
       BOOL OpenCurRecordset(CString strTableName);
       BOOL RefreshColumn(ULONG *pulColCount);
       BOOL RefreshData(ULONG ulColCount);
       BOOL GetInfoArray(CString strTableName, CUIntArray &uaID,CStringArray &saArray);
       BOOL InsertRow(CString strTableName, CStringArray &saValues);
       BOOL DeleteRow(CString strTableName, CString strColName,CString strValue);
       CString VariantToCtring(VARIANT var);
       BOOL ConstructVar(CString strValue, int type, VARIANT *var);
    下面分别介绍这些函数的功能和实现过程。
    (1) 函数OpenCurRecordset
    函数OpenCurRecordset用于将特定的表打开,结果集存放在_RecordsetPtr对象里,参数strTableName表示表的名称。
    函数在打开结果集的时候使用的是m_recordset对象的Open方法,参数表明采用了adOpenDynamic、adLockOptimistic和adCmdText模式。
    OpenCurRecordset函数的实现代码如下:

    //OpenCurRecordset:特定表的打开,结果集存放在_RecordsetPtr所指的对象里
    //参数(Sql):查询语句
    //返回值:Bool型,用来表示打开成功与否
    BOOL CMemberSystemView::OpenCurRecordset(CString strTableName)
    {
       // 有效性检验
       if(!m_fConnected)
          return FALSE;
       if(strTableName.IsEmpty())
          return FALSE;
       HRESULT hr;
       // 构造查询语句(OpenCurRecordset函数也可以直接以sql语句为参数,以支持复杂查询)
       CString strQuery;
       strQuery.Format("select * from %s", strTableName);

       //_bstr_t query = Sql;   //用户使用的SQL语句(CString参数)

       _bstr_t query = strQuery;
       _bstr_t source =  m_strSource;
       try{
           //不能打开已打开的记录集,否则报“Unknown Error 0x800A0E79”错误
           if(m_recordset->State == adStateOpen)
               m_recordset->Close();//adStateClosed

           //或者使用 if (m_recordset->State )   m_recordset->Close();
           hr = m_recordset->Open(query, source, adOpenDynamic,adLockOptimistic, adCmdText);
       }
       catch (_com_error &e){
            CString errormessage;
            errormessage.Format("打开记录集失败!\r\n错误信息:%s",e.ErrorMessage());
            AfxMessageBox(errormessage);//或MessageBox,显示错误信息,测试错误出在那个函数中
            return FALSE;
       }
       return (SUCCEEDED(hr));
    }
    (2) 函数RefreshColumn
    RefreshColumn函数通过m_recordset对象的get_Fields方法取得对象的列集,从该列集里得到结果集的列信息,并插入到界面中列表视图的列里。
    RefreshColumn函数的代码如下:    
    BOOL CMemberSystemView::RefreshColumn(ULONG *pulColCount)
    {
       // 有效性检验
       if(!m_fConnected)
          return FALSE;
       HRESULT hr;
       CListCtrl &listCtrl = GetListCtrl();

       listCtrl.DeleteAllItems();//首先清空列表控件原有的内容

       //DWORD exstyle = listCtrl.GetExtendedStyle();      
       //listCtrl.SetExtendedStyle(exstyle|LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES

                 | LVS_EX_CHECKBOXES | WS_EX_STATICEDGE);
       listCtrl.ModifyStyle(0,LVS_REPORT|LVS_SHOWSELALWAYS);//|LVS_SORTASCENDING使显示不正常
       listCtrl.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE,0,LVS_EX_GRIDLINES

                 |LVS_EX_FULLROWSELECT);
       CString strColName;//保存列名
       Fields* fields = NULL;//保存记录集中的所有Field
       try{
           // 取结果集的列集
           hr = m_recordset->get_Fields(&fields);
           if (SUCCEEDED(hr))
               hr = fields->get_Count((long *)pulColCount);//获取列数

           //-把列名在List控件中显示-//
           int index;

           for(long i=0;i<*pulColCount;i++)
           {
               BSTR bstrColName;
               hr = fields->Item[i]->get_Name(&bstrColName);
               strColName = bstrColName;
               // 插入列表视图的列
               int nWidth = listCtrl.GetStringWidth(strColName) + 25;
               index = listCtrl.InsertColumn(i, strColName, LVCFMT_LEFT, nWidth);
           }
           // 释放列集
           if (SUCCEEDED(hr))
              fields->Release();
        }
        catch (_com_error &e)
        {
           MessageBox("RefreshColumn  error");//测试错误出在那个函数中

           MessageBox(e.ErrorMessage());
           return FALSE;
        }
        return (SUCCEEDED(hr));
    }
    (3) 函数RefreshData
    RefreshData函数通过调用m_recordset对象的get_adoEOF方法获知当前的结果集光标的位置是否在结果集末尾,使用 get_Item方法取得一个field对象,该对象里存放了列的数据类型和数据,我们可以通过get_Value方法取得它的值,使用 VariantToCtring函数将这个VARIANT类型的值转换成CString类型的值,VariantToCtring函数我们还要在后面介 绍,函数最后调用m_recordset对象的Close方法关闭结果集。
    RefreshData函数的实现代码如下:
    BOOL CMemberSystemView::RefreshData(ULONG ulColCount)
    {
       // 有效性检验
       if(!m_fConnected)
          return FALSE;
       if(0 == ulColCount)
          return FALSE;
       //- 变量定义 -//

       HRESULT hr;
       CListCtrl &listCtrl = GetListCtrl();//获取视图控件
       CString strValue;
       VARIANT var_value;
       VARIANT_BOOL ValEof;//是否还有记录
       int nRowCount = 0;
       Field *field = NULL;
       VARIANT varCounter;

       varCounter.vt = VT_I4;//有关VARIANT类型的说明请见MSDN的CComVariant
       varCounter.lVal = 0;
       try{
           // 取当前光标位置是否在结果集末尾
           ValEof = m_recordset->get_adoEOF(&ValEof);

           //hr = m_recordset->get_adoEOF(&ValEof);该代码作用与上相同
           while(TRUE){
               if(ValEof) break;
               varCounter.lVal = 0;
               // 取一个列对象
               m_recordset->Fields->get_Item(varCounter, &field);
               //DataTypeEnum data_type;               
               field->get_Value(&var_value);// 取列对象的值
               // 转换成字符类型
               strValue = VariantToCtring(var_value);
               // 插入到界面列表视图里
               listCtrl.InsertItem(nRowCount, strValue);

               //int Colcount = (int)ulColCount;
               //for (long i = 1; i < Colcount; i++)
               for(int i=1;i<ulColCount;i++){
                   varCounter.lVal = i;
                   m_recordset->Fields->get_Item(varCounter, &field);
                   field->get_Value(&var_value);
                   strValue = VariantToCtring(var_value);
                   listCtrl.SetItemText(nRowCount, i, strValue);
               }
               nRowCount ++;
               m_recordset->MoveNext();
               m_recordset->get_adoEOF(&ValEof);
           }
           // 关闭结果集
           m_recordset->Close();
        }
        catch (_com_error &e){

           MessageBox("RefreshData  error");//测试错误出在那个函数中
           MessageBox(e.ErrorMessage());
           return FALSE;
        }
        return (SUCCEEDED(hr));
    }
    (4) 函数GetInfoArray
    GetInfoArray函数实现了从特定表的特定列里得到需要的信息,参数strTableName为输入的表的名称,参数uaID为输出的关键字列里的ID,参数saArray为输出列的名称。
    GetInfoArray函数的实现代码如下:
    BOOL CMemberSystemView::GetInfoArray(CString strTableName,CUIntArray &uaID,

            CStringArray &saArray)
    {
        // 有效性检验
        if(!m_fConnected)
           return FALSE;
        HRESULT hr;
        CString strQuery;
        CString strValue;
        VARIANT var_value;
        VARIANT_BOOL ValEof;
        int nRowCount = 0;
        Field *field = NULL;
        _variant_t var_t;
        _bstr_t bst_t;
        VARIANT varCounter;
        varCounter.vt = VT_I4;
        varCounter.lVal = 0;
        // 建立查询字符串
        strQuery.Format("select * from %s", strTableName);
        _bstr_t query = strQuery;
        _bstr_t source =  m_strSource;
        try{
            // 打开结果集
            hr = m_recordset->Open(query, source, adOpenDynamic,adLockOptimistic, adCmdText);
            ValEof = m_recordset->get_adoEOF(&ValEof);
            while(TRUE){
               if(ValEof) break;
               varCounter.lVal = 0;
               // 读取字段内容,第1个字段为整型的行标识,如社团ID,第2个字段为社团名等字串
               m_recordset->Fields->get_Item(varCounter, &field);
               field->get_Value(&var_value);
               uaID.Add(var_value.lVal);
               varCounter.lVal = 1;
               m_recordset->Fields->get_Item(varCounter, &field);
               field->get_Value(&var_value);
               var_t = var_value;
               bst_t = var_t;
               saArray.Add((const char *)bst_t);
               nRowCount ++;
               m_recordset->MoveNext();
               m_recordset->get_adoEOF(&ValEof);
            }
            // 关闭结果集
            m_recordset->Close();
         }
         catch (_com_error &e){
            MessageBox(e.ErrorMessage());
            return FALSE;
         }
         return (SUCCEEDED(hr));
    }
    (5) 函数InsertRow
    InsertRow函数将存放在CstringArray数组里的列值添加到strTableName表里。函数首先是打开一个结果集,然后执行结果集的 插入方法AddNew,该函数只是为m_recordset对象增加了一个空的列对象,我们需要将列的值拷贝到这个列对象里,field对象的 put_Value方法可以实现列对象的复制,但是它的参数是VARIANT类型的,我们编写了ConstructVar函数将一个特定类型的值转换成 VARIANT类型。
    InsertRow函数的实现代码如下:
    BOOL CMemberSystemView::InsertRow(CString strTableName,CStringArray &saValues)
    {
        // 有效性检验
        if(!m_fConnected) return FALSE;
        if(strTableName.IsEmpty()) return FALSE;
        int nColNum = 0;
        if(0 == (nColNum = saValues.GetSize())) return FALSE;
        HRESULT hr;
        Fields* fields = NULL;
        Field* field = NULL;
        VARIANT varValue;
        VARIANT varCount;
        DataTypeEnum data_type;
        varCount.vt = VT_I4;
        // 打开结果集
        //CString tempstr;//测试用
        if(!OpenCurRecordset(strTableName)) return FALSE;
        try{
            hr = m_recordset->AddNew();
            hr = m_recordset->get_Fields(&fields);
            for(int i=0;i<nColNum;i++)
            
                varCount.lVal = i+1;//因为第1个字段为自增字段,不需要赋值
                hr = fields->get_Item(varCount, &field);  
                field->get_Type(&data_type);
                if(!ConstructVar(saValues.GetAt(i), data_type, &varValue))
                    return FALSE;
                hr = field->put_Value(varValue);
                //tempstr=tempstr+saValues.GetAt(i)+"  ";//测试用
            }
            m_recordset->Update();//将修改后的记录保存到数据库
            //MessageBox(tempstr);
            fields->Release();
            field->Release();
        }
        catch (_com_error &e){
           MessageBox(e.ErrorMessage());
           return FALSE;
        }
        return (SUCCEEDED(hr));

    }
    (6) 函数DeleteRow
    DeleteRow函数将特定的行从strTableName表里删除。
    函数利用输入的strIDColName列名称和strValue列值建立查询语句,从而由这个查询语句建立一个结果集,将结果集的记录删除就可以实现删除行操作。m_recordset对象的Delete方法将结果集当前行从结果集中删除。
    DeleteRow函数的实现代码如下:
    BOOL CMemberSystemView::DeleteRow(CString strTableName,CString strColName,

           CString strValue)
    {
        // 有效性检验
        if(!m_fConnected) return FALSE;
        HRESULT hr;
        CString strQuery;
        VARIANT_BOOL ValEof;
        // 构造SQL查询语句,注意字串类型的字段值要加单引号,否则报错
        strQuery.Format("select * from %s where %s='%s'",strTableName,strColName,strValue);
        _bstr_t query = strQuery;
        _bstr_t source =  m_strSource;
        try{
            hr = m_recordset->Open(query, source, adOpenDynamic,adLockOptimistic, adCmdText);
            ValEof = m_recordset->get_adoEOF(&ValEof);
            if(!ValEof) m_recordset->Delete(adAffectCurrent);//删除当前行
            m_recordset->Close();//关闭记录集的同时,记录集被重新写回数据库
        }
        catch (_com_error &e){
            //MessageBox(strQuery);
            //MessageBox("deleterow error");//测试错误出现位置
            MessageBox(e.ErrorMessage());
            return FALSE;
        }
        return (SUCCEEDED(hr));

    }
    (7) 函数VariantToCtring
    函数VariantToCtring实现了将VARIANT类型的值转换成CString类型。
    VariantToCtring函数的实现代码如下:
    CString CMemberSystemView::VariantToCtring(VARIANT var)
    {
       CString strValue;
       _variant_t var_t;
       _bstr_t bst_t;
       time_t cur_time;
       CTime time_value;
       COleCurrency var_currency;
       switch(var.vt){
           case VT_EMPTY: strValue = _T(""); break;
           case VT_UI1: strValue.Format("%d", var.bVal); break;
           case VT_I2: strValue.Format("%d", var.iVal); break;
           case VT_I4: strValue.Format("%d", var.lVal); break;
           case VT_R4: strValue.Format("%f", var.fltVal); break;
           case VT_R8: strValue.Format("%f", var.dblVal); break;
           case VT_CY:
              var_currency = var;
              strValue = var_currency.Format(0);
              break;
           case VT_BSTR:
              var_t = var;
              bst_t = var_t;
              strValue.Format("%s", (const char *)bst_t);
              break;
           case VT_NULL: strValue = _T(""); break;
           case VT_DATE:
              //cur_time = var.date;
              //time_value = cur_time;
              //strValue = time_value.Format("%A, %B %d, %Y");

              //strValue = time_value.Format("%Y-%m-%d");

              //以上语句不能取得日期字段值,固定显示“1970-1-1”
              //time_value = CTime::GetCurrentTime();
              //strValue = time_value.Format("%Y-%m-%d");
               {
                 DATE dt=var.date;//在case中初始化变量的时候整体要加个大括号            
                 COleDateTime   odt    COleDateTime(dt);
                 strValue = odt.Format("%Y-%m-%d   %H:%M:%S");
               }
              break;
           case VT_BOOL: strValue.Format("%d", var.boolVal); break;
           default: strValue = _T(""); break;
       }
       return strValue;

    }
    (8) 函数ConstructVar
    函数ConstructVar实现了VariantToCtring函数的反向功能,将CString类型的值根据转换类型转换成为VARIANT值。
    函数ConstructVar实现代码如下:
    BOOL CMemberSystemView::ConstructVar(CString strValue, int type, VARIANT *var)
    {
       COleDateTime var_date;
       CURRENCY cy;
       cy.Hi = 0;
       switch(type){
          case adInteger:
          case adSmallInt:   
             var->vt = VT_I4;
             var->lVal = atoi(strValue);
             break;
          case adCurrency://6
             //var->vt = VT_CY;
             //cy.Lo = atoi(strValue);
             //cy.int64 = atoi(strValue);
             //var->cyVal = cy;
             //以上代码好像数据转换不正确
             {
                //有关数据转换的知识扩充
                //CString   str;  
                //COleCurrency   cur;    
                //String   To   Currency:  
                //_variant_t   var(str);  
                //var.ChangeType(VT_CY);  
                //cur    var.cyVal;  
   
                //Currency   To   String:  
                //_variant_t   var(cur);  
                //var.ChengeType(VT_BSTR);  
                //str    var.bstrVal;
                //以下代码测试通过
                _variant_t   _var(strValue);  
                _var.ChangeType(VT_CY);  
                *var    _var;
             }
             break;
          case adChar:
          case adVarWChar:
             var->vt = VT_BSTR;
             var->bstrVal = (_bstr_t)strValue;
             break;
          case adDBTimeStamp:
             {
                   //CString转换COleDateTime
                   //CString strDate = "2008-12-8";
                  //CString strTime = "12:50:40";
                  //COleDateTime t;
                  //t.ParseDateTime( strDate + CString(" ") + strTime );
                  var_date.ParseDateTime(strValue);
                  var->vt = VT_DATE;
                  var->date = var_date;
             }
             break;
          default:
             var->vt = VT_EMPTY;
             break;
       }
       return TRUE;

    }

 

参考文章:

1、COleCurrency和CString之间如何相互转换 http://topic.csdn.net/t/20030117/11/1367939.html

2、recordset Unknown Error 0x800A0E79 http://topic.csdn.net/t/20060518/12/4760796.html

3、有关ADO调用存储过程 http://www.roarsoft.net/html/article/article_92_485.htm

4、判断数据库数据类型 http://hi.baidu.com/ilotus_y/blog/item/414b04b7918367f131add194.html

5、VC 数据库编程三部教学 http://download.csdn.net/source/1254266 

posted @ 2011-08-19 21:14  luoshupeng  阅读(517)  评论(0编辑  收藏  举报