ODBC

作者: downdemo | 来源:发表于2018-03-19 10:24 被阅读14次

    几个常用类

    • afxdb.h
      • CDBException:CException 171-197
      • CDatabase:CObject 204-318
      • CFieldExchange 322-401
      • CRecordset:CObject 556-957
      • CDBVariant 1025-1056
      • CRecordView:CFormView 1061-1101
    • 1.0Set.cpp
      • CMy10Set:CRecordset
      • GetDefaultConnect()
      • GetDefaultSQL()
      • DoFieldExchange // RFX
      • AssertValid()
      • Dump()

    构建数据源

    • 控制面板-管理工具-ODBC数据源64位
    • 建立ODBC数据源-连接数据库-选择和处理记录-数据库应用程序中的文档与视图
    • ODBC数据源-系统DSN-添加Access-数据源名My_DataSource-确定
    • 访问数据要连接数据源,连接封装到CDatabase类中
    • 连接后可以
      • 构造CRecordset派生类对象,从数据库中读取相应记录,保存在CRecordset派生类中
      • 管理事务
      • 执行SQL
    • 要正确使用CDatabase必须在ODBC数据源控制台中正确注册,同意程序可以有多个数据源,对应多个CDatabase对象,也可以用多个CDatabase对象连接同一数据源
    • CRecordset一般要派生出一个新子类,在CRecordset派生类中的数据对应数据库中相应的行
    • 用户要重载CRecordset类中的GetDefaultSQL函数来返回使用的表的名字
    • CRecordset对象负责定制SQL、在数据库中移动记录指针、增删改查,不需要时就要释放CRecordset对象
    • 视图文档结构:视图显示数据,文档对象(有多个)存取不同的数据,视图还负责和文档的数据交换和更新。有时这样的结构多余,如当只操作一个数据源中的一个数据库,数据放在视图类中就行了
    • 新建一个表My_Access_DB,作者、出版社、价格,内容自填
    • 新建MFC-单文档-文件支持+ODBC+选择数据源-新建DSN(.mdb)-浏览位置,取名My_1.0,完成-进入ODBC Access安装-数据库:选择-选择之前建好的表

    关联编辑框控件和数据

    • 建DIALOG,4个Static Text+4个Edit Control,关联完即可显示
    • 1.0set.h
      • CMy10Set:CRecordset
        • long m_ID
        • CStringW column1
        • CStringW column2
        • double column3
        • GetDefaultConnect()
        • GetDefaultSQL()
        • DoFieldExchange()
        • AssertValid()
        • Dump()
    • 1.0View.cpp
      • CMy10View:CRecordView
      • DoDataExchange() // 关联编辑框控件和数据库字段,使用下面的函数关联
        • DDX_FieldText(pDX, IDC_EDIT1, m_pSet->m_ID, m_pSet)
        • DDX_FieldText(pDX, IDC_EDIT2, m_pSet->column1, m_pSet)_
      • PreCreateWindow()
      • OnInitialUpdate()
      • OnFilePrintPreview()
      • OnPreparePrinting()
      • OnBeginPrinting()
      • OnEndPrinting()
      • OnRButtonUp()
      • OnContextMenu()
      • AssertValid()
      • Dump()
      • GetDocument()
      • OnGetRecordset()

    菜单项更新和删除

    • Resource View-1.0.rc-Menu-IDR_MAINFRAME
    • 加入三个菜单项,分别为删除、更新、清空,为其分配ID如下,并右键添加Event Handler
      • ID_DELETE_RECORD
      • ID_UPDATE_RECORD
      • ID_CLEAR_DOMAIN
    • 第一个COMMAMD
    void CMy10View::OnDeleteRecord()
    {
        // TODO: Add your command handler code here
        CRecordsetStatus m_cStatus;
        try{ m_pSet->Delete();  }
        catch (CDBException* m_pEx)
        {
            AfxMessageBox(m_pEx->m_strError);
            m_pEx->Delete();
            m_pSet->MoveFirst(); // 失败则将记录指针移到开头
            UpdateData(FALSE);
            return;
        }
    
        m_pSet->GetStatus(m_cStatus);
        if (m_cStatus.m_lCurrentRecord == 0)
            m_pSet->MoveFirst();
        else
            m_pSet->MoveNext();
        UpdateData(FALSE);
    }
    
    • 第一个UPDATE_COMMAND_UI
    void CMy10View::OnUpdateDeleteRecord(CCmdUI *pCmdUI)
    {
        // TODO: Add your command update UI handler code here
        pCmdUI->Enable(!m_pSet->IsEOF());
    }
    
    • 第二个COMMAND
    void CMy10View::OnUpdateRecord()
    {
        // TODO: Add your command handler code here
        m_pSet->Edit();
        UpdateData(TRUE);
        if (m_pSet->CanUpdate()) // 记录可更新则返回非零值
            m_pSet->Update();
    }
    
    • 第二个UPDATE_COMMAND_UI
    void CMy10View::OnUpdateUpdateRecord(CCmdUI *pCmdUI)
    {
        // TODO: Add your command update UI handler code here
        pCmdUI->Enable(!m_pSet->IsEOF());
    }
    
    • 第三个COMMAND
    void CMy10View::OnClearDomain()
    {
        // TODO: Add your command handler code here
        m_pSet->SetFieldNull(NULL);
        UpdateData(FALSE);
    }
    

    重载OnMove

    • Class View-右键CMy10View,Class Wizard-Virtual Functions-双击左边的OnMove会出现到右边的重写虚函数的列表中,Edit Code
    BOOL CMy10View::OnMove(UINT nIDMoveCommand)
    {
        // TODO: Add your specialized code here and/or call the base class
        switch (nIDMoveCommand)
        {
            case ID_RECORD_PREV:
                if (!m_pSet->IsBOF())
                    m_pSet->MovePrev();
                break;
            case ID_RECORD_FIRST:
                m_pSet->MoveFirst();
                break;
            case ID_RECORD_NEXT:
                if (!m_pSet->IsEOF())
                    m_pSet->MoveNext();
                break;
            case ID_RECORD_LAST:
                m_pSet->MoveLast();
                break;
            default:
                ASSERT(FALSE);
        }
        UpdateData(FALSE);
        return CRecordView::OnMove(nIDMoveCommand);
    }
    

    菜单项添加

    • 给菜单项加一个选项,ID设为ID_ADD_RECORD
    • 在class view中,右键Set类,选择Add-Add Functions
    • 添加函数名为GetMaxID
    • 在xxxSet.cpp中即可看到添加的函数,修改如下
    int CMy10Set::GetMaxID()
    {
        MoveLast(); // 移到最后一条记录
        return m_ID;
    }
    
    • 右键新的菜单项,Event Handler添加COMMAND消息
    void CMy10View::OnAddRecord()
    {
        // TODO: Add your command handler code here
        CRecordset* pSet = OnGetRecordset(); // 获取指向数据库的指针
        if (pSet->CanUpdate() && !pSet->IsDeleted())
        {
            pSet->Edit();
            if (!UpdateData()) return;
            pSet->Update();
        }
        long m_INewID = m_pSet->GetMaxID() + 1; // 获取新ID值
        m_pSet->AddNew(); // 添加一个新记录
        m_pSet->m_ID = m_INewID;
        m_pSet->Update(); // 保存新记录
        m_pSet->Requery(); // 刷新数据库
        m_pSet->MoveLast();
        UpdateData(FALSE); // 更新表单
    }
    

    菜单项浏览和排序

    • 新建一个Dialog,ID改为IDD_MOVE_RECORD,右键Add Class,类名为CMoveToRecord,在MoveToRecord.h中#include "resource.h"
    • 添加一个Static Text和Edit Control,Edit Control的ID设置为IDC_RECORD_ID
    • 给Edit Control添加一个变量m_RecordID,Category设置为Value,类型设置为long


    • 增加菜单项如下,ID设置为ID_MOVEToRecord


    • 添加COMMAND消息CMy10View::OnMovetorecord(),在视图类1.0View.cpp中#include "MoveToRecord.h"

    • 打开Resource View-Tool Bar-IDR_MAINFRAME,添加一个按钮,点击上方的A(Text Tool)输入字符为M,ID选择为ID_MOVEToRecord

    • 接着响应前一步的COMMAND消息
    void CMy10View::OnMovetorecord()
    {
        // TODO: Add your command handler code here
        CMoveToRecord dlgMoveTo;
        if (dlgMoveTo.DoModal() == IDOK)
        {
            CRecordset *pSet = OnGetRecordset();
            pSet->SetAbsolutePosition(dlgMoveTo.m_RecordID);
            UpdateData(FALSE);
        }
    }
    
    • 此时运行就可以使用移动到某条记录的功能了,接下来是排序。在CRecordSet和其派生类中有一个m_strSort成员,决定了记录的排序。在菜单项中添加菜单项“按价格排序”,ID设为ID_SORT_PRICE,映射COMMAND消息处理函数OnSortPrice(),之后运行就是按价格递增的排序了
    void CMy10View::OnSortPrice()
    {
        // TODO: Add your command handler code here
        // TODO: Add your command handler code here
        m_pSet->Close(); // 关闭数据库
        m_pSet->m_strSort = "价格";
        m_pSet->Open();
        UpdateData(FALSE); // 更新已排序过的记录
    }
    

    相关文章

      网友评论

          本文标题:ODBC

          本文链接:https://www.haomeiwen.com/subject/wieuqftx.html