MFC操作数据库有关的类

我知道CDatabase和CRecordSet两个类,然后还有插入和删除和更新要用什么类来操作?

菜菜爱榴莲 2021-09-18 16:36 490 次浏览 赞 147

最新问答

  • 小草儿嬢嬢

    1、 MFC的ODBC类简介
      MFC的ODBC类对较复杂的ODBC API进行了封装,了简化的调用接口,从而大大方便了库应用程序的开发。程序员不必了解ODBC API和SQL的具体细节,利用ODBC类即可完成对库的大部分作。
      MFC的ODBC类主要包括:
    CDatabase类:主要功能是建立与源的连接。
    CRecordset类:该类代表从源选择的一组记录(记录集),程序可以选择源中的某个表作为一个记录集,也可以通过对表的查询得到记录集,还可以合并同一源中多个表的列到一个记录集中.通过该类可对记录集中的记录进行滚动、修改、增加和删除等作。
    CRecordView类:了一个表单视图与某个记录集直接相连,利用对话框交换机制(DDX)在记录集与表单视图的控件之间传输。该类支持对记录的浏览和更新,在撤销时会自动关闭与之相联系的记录集。
    CFieldExchange类:支持记录字段交换(DFX),即记录集字段成员与相应的库的表的字段之间的交换。该类的功能与CDataExchange类的对话框交换功能类似。
    CDBException类:代表ODBC类产生的异常。
      概括地讲,CDatabase针对某个库,它负责连接源;CRecordset针对源中的记录集,它负责对记录的作;CRecordView负责界面,而CFieldExchange负责CRecordset与源的交换。
      利用AppWizard和ClassWizard,用户可以方便地建立库应用程序,但这并不意味着可以对MFC的ODBC类一无所知.读者应注意阅读后面几小节中的内容,为学习后面的例子打好基础.
    2、 CDatabase类
      要建立与源的连接,首先应构造一个CDatabase对象,然后再调用CDatabase的Open成员函数.Open函数负责建立连接,其声明为
    virtual BOOL Open( LPCTSTR lpszDSN, BOOL bExclusive = FALSE, BOOL bReadOnly = FALSE, LPCTSTR lpszConnect = “ODBC;”, BOOL bUseCursorLib = TRUE ); throw( CDBException, CMemoryException );
       参数lpszDSN指定了源名(构造源的方法将在后面介绍),在lpszConnect参数中也可包括源名,此时lpszDSN必需为 NULL,若在函数中未源名且使lpszDSN为NULL,则会显示一个源对话框,用户可以在该对话框中选择一个源.参数 bExclusive说明是否独占源,由于目前版本的类库还不支持独占方式,故该参数的值应该是FALSE,这说明源是被共享的.参数 bReadOnly若为TRUE则对源的连接是只读的.参数lpszConnect指定了一个连接字符串,连接字符串中可以包括源名、用户帐号 (ID)和口令等信息,字符串中的"ODBC"表示要连接到一个ODBC源上.参数bUseCursorLib若为TRUE,则会装载光标库,否则不 装载,快照需要光标库,动态集不需要光标库. 若连接成功,函数返回TRUE,若返回FALSE,则说明用户在源对话框中按了Cancel按钮。若函数内部出现错误,则框架会产生一个异常。
      下面是一些调用Open函数的例子。
    CDatabase m_db; //在文档类中嵌入一个CDatabase对象
    //连接到一个名为"Student Registration"的源
    m_db.Open("Student Registration");
    //在连接源的同时指定了用户帐号和口令
    m_db.Open(NULL,FALSE,FALSE,"ODBC;DSN=Student Registration;UID=ZYF;PWD=1234");
    m_db.Open(NULL); //将弹出一个源对话框
     
      要从一个源中脱离,可调用函数Close。在脱离后,可以再次调用Open函数来建立一个新的连接.调用IsOpen可判断当前是否有一个连接,调用GetConnect可返回当前的连接字符串。函数的声明为
    virtual void Close( );
    BOOL IsOpen( ) const; //返回TRUE则表明当前有一个连接
    const CString& GetConnect( ) const;
      CDatabase的析构函数会调用Close,所以只要删除了CDatabase对象就可以与源脱离。

    3、CRecordset类
      CRecordset类代表一个记录集.该类是MFC的ODBC类中最重要、功能最强大的类。
    10.5.1 动态集、快照、光标和光标库
       在多任务作系统或网络环境中,多个用户可以共享同一个源。共享的一个主要问题是如何协调各个用户对源的修改。例如,当某一个应用改变了数 据源中的记录时,别的连接至该源的应用应该如何处理。对于这个问题,基于MFC的ODBC应用程序可以采取几种不同的处理办法,这将由程序采用哪种记 录集决定。
      记录集主要分为快照(Snapshot) 和动态集(Dynaset)两种,CRecordset类对这两者都支持。这两种记录集的不同表现在它们对别的应用改变源记录采取了不同的处理方法。
       快照型记录集了对的静态视.快照是个很形象的术语,就好象对源的某些记录照了一张照片一样.当别的用户改变了记录时(包括修改、和删 除),快照中的记录不受影响,也就是说,快照不反映别的用户对源记录的改变.直到调用了CRecordset::Requery重新查询后,快照才会 反映变化.对于象产生报告或执行计算这样的不希望中途变动的工作,快照是很有用的。需要指出的是,快照的这种静态特性是相对于别的用户而言的,它会正确反 映由本身用户对记录的修改和删除,但对于新的记录直到调用Requery后才能反映到快照中.
       动态集了的动态视.当别的用户修改或删除了记录集中的记录时,会在动态集中反映出来:当滚动到修改过的记录时对其所作的修改会立即反映到动态集 中,当记录被删除时,MFC代会跳过记录集中的删除部分.对于其它用户的记录,直到调用Requery时,才会在动态集中反映出来。本身应用程序对 记录的修改、和删除会反映在动态集中。当必须是动态的时侯,使用动态集是最适合的。例如,在一个火车票联网票系统中,显然应该用动态集随时反映 出共享的变化。
      在记录集中滚动,需要有一个标志来指明滚动后的位置(当前位置)。ODBC驱动程序会维护一个光标,用来记录集的当前记录,可以把光标理解成记录集位置的一种机制。
       光标库(Cursor Library)是处于ODBC驱动程序管理器和驱动程序之间的动态链接库(ODBCCR32.DLL).光标库的主要功能是支持快照以及为底层驱动程序 双向滚动能力,高层次的驱动程序不需要光标库,因为它们是可滚动的.光标库管理快照记录的缓冲区,该缓冲区反映本程序对记录的修改和删除,但不反映其 它用户对记录的改变,由此可见,快照实际上相当于当前的光标库缓冲区.
      应注 意的是,快照是一种静态光标(Static Cursor).静态光标直到滚动到某个记录才能取得该记录的.因此,要保证所有的记录都被快照,可以先滚动到记录集的末尾,然后再滚动到感兴趣的第 一个记录上.这样做的缺点是滚动到末尾需要额外的开销,会降低性能.
      与快照不同,动态集不用光标库维持的缓冲区来存放记录.实际上,动态集是不使用光标库的,因为光标库会屏蔽掉一些支持动态集的底层驱动程序功能.动态集是一种键集驱动光标(Keyset-Driven Cursor),当打开一个动态集时,驱动程序保存记录集中每个记录的键.只要光标在动态集中滚动,驱动程序就会通过键来从源中检取当前记录,从而保证选取的记录与源同步.
      从上面的分析中可以看出,快照和动态集有一个共同的特点,那就是在建立记录集后,记录集中的成员就已经确定了.这就是为什么两种记录集都不能反映别的用户记录的原因.
    10.5.2 域成员与交换
       CRecordset类代表一个记录集.用户一般需要用ClassWizard创建一个CRecordset的派生类.ClassWizard可以为派 生的记录集类创建一批成员,这些成员与记录的各字段相对应,被称为字段成员或域成员.例如,对于表10.2所示的将在后面例子中使用的数 据库表,ClassWizard会在派生类中加入6个域成员
    10.5.3 SQL查询
       记录集的建立实际上主要是一个查询过程,SQL的SELECT语句用来查询源.在建立记录集时,CRecordset会根据一些参数构造一个 SELECT语句来查询源,并用查询的结果创建记录集.明白这一点对理解CRecordset至关重要.SELECT语句的句法如下:
    SELECT r-field-list FROM table-name [WHERE m_strFilter]
    [ORDER BY m_strSort]
      其中table-name是表名,r-field-list是选择的列(字段).WHERE和ORDER BY是两个子句,分别用来过滤和排序。下面是SELECT语句的一些例子:
    SELECT CourseID, InstructorID FROM Section
    SELECT * FROM Section WHERE CourseID=‘MATH202’ AND Capacity=15
    SELECT InstructorID FROM Section ORDER BY CourseID ASC
       其中第一个语句从Section表中选择CourseID和InstructorID字段.第二个语句从Section表中选择CourseID为 MATH202且Capacity等于15的记录,在该语句中使用了象"AND"或"OR"这样的逻辑连接符.要注意在SQL语句中引用字符串、日期或时 间等类型的时要用单引号括起来,而数值型则不用.第三个语句从Section表中选择InstructorID列并且按CourseID的升序排 列,若要降序排列,可使用关键字DESC.
    提示:如果列名或表名中包含有空格,则必需用方括号把该名称包起来。例如,如果有一列名为“Client Name”,则应该写成“[Client Name]”。
     
    10.5.4 记录集的建立和关闭
      要建立记录集,首先要构造一个CRecordset派生类对象,然后调用Open成员函数查询源中的记录并建立记录集.在Open函数中,可能会调用GetDefaultConnect和GetDefaultSQL函数.函数的声明为
    CRecordset( CDatabase* pDatabase = NULL);
    参数pDatabase指向一个CDatabase对象,用来获取源.如果pDatabase为NULL,则会在Open函数中自动构建一个 CDatabase对象.如果CDatabase对象还未与源连接,那么在Open函数中会建立连接,连接字符串(参见10.3.1)由成员函数 GetDefaultConnect.
    virtual CString GetDefaultConnect( );
    该函数返回缺省的连接字符串.Open函数在必要的时侯会调用该函数获取连接字符串以建立与源的连接.一般需要在CRecordset派生类中覆盖该函数并在新版的函数中连接字符串.
    virtual BOOL Open( UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE, LPCTSTR lpszSQL = NULL, DWORD dwOptions = none );
    throw( CDBException, CMemoryException );
    该函数使用指定的SQL语句查询源中的记录并按指定的类型和选项建立记录集.参数nOpenType说明了记录集的类型,如表10.3所示,如果要求 的类型驱动程序不支持,则函数将产生一个异常.参数lpszSQL是一个SQL的SELECT语句,或是一个表名.函数用lpszSQL来进行查询,如果 该参数为NULL,则函数会调用GetDefaultSQL获取缺省的SQL语句.参数dwOptions可以是一些选项的组合,常用的选项在表10.4 中列出.若创建成功则函数返回TRUE,若函数调用了CDatabase::Open且返回FALSE,则函数返回FALSE.
     
    表10.3 记录集的类型

    类型

    含义

    AFX_DB_USE_DEFAULT_TYPE

    使用缺省值.

    CRecordset::dynaset

    可双向滚动的动态集.

    CRecordset::snapshot

    可双向滚动的快照.

    CRecordset::dynamic

    比动态集更好的动态特性,大部分ODBC驱动程序不支持这种记录集.

    CRecordset::forwardOnly

    只能前向滚动的只读记录集.

     
     
    表10.4 创建记录集时的常用选项

    选项

    含义

    CRecordset::none

    无选项(缺省).

    CRecordset::appendOnly

    不允许修改和删除记录,但可以记录.

    CRecordset::readOnly

    记录集是只读的.

    CRecordset::skipDeletedRecords

    有些库(如FoxPro)在删除记录时并不真删除,而是做个删除标记,在滚动时将跳过这些被删除的记录.

     
     
    virtual CString GetDefaultSQL( );
    Open函数在必要时会调用该函数返回缺省的SQL语句或表名以查询源中的记录.一般需要在CRecordset派生类中覆盖该函数并在新版的函数中SQL语句或表名.下面是一些返回字符串的例子.
    “Section” //选择Section表中的所有记录到记录集中
    “Section, Course” //合并Section表和Course表的各列到记录集中
    //对Section表中的所有记录按CourseID的升序进行排序,然后建立记录集
    “SELECT * FROM Section ORDER BY CourseID ASC”
      上面的例子说明,通过合理地安排SQL语句和表名,Open函数可以十分灵活地查询源中的记录.用户可以合并多个表的字段,也可以只选择记录中的某些字段,还可以对记录进行过滤和排序.
       上一小节说过,在建立记录集时,CRecordset会构造一个SELECT语句来查询源.如果在调用Open时只了表名,那么SELECT语 句还缺少选择列参数r-field-list(参见10.5.3).框架规定,如果只了表名,则选择列的信息从DoFieldExchange中 的RFX语句里提取.例如,如果在调用Open时只了"Section"表名,那么将会构造如下一个SELECT语句:
    SELECT CourseID,SectionNo,InstructorID,RoomNo, Schedule,Capacity FROM Section
     
      建立记录集后,用户可以随时调用Requery成员函数来重新查询和建立记录集.Requery有两个重要用途:
    使记录集能反映用户对源的改变(参见10.5.1).
    按照新的过滤或排序方法查询记录并重新建立记录集.
     
      在调用Requery之前,可调用CanRestart来判断记录集是否支持Requery作.要记住Requery只能在成功调用Open后调用,所以程序应调用IsOpen来判断记录集是否已建立.函数的声明为
    virtual BOOL Requery( );throw( CDBException, CMemoryException );
    返回TRUE表明记录集建立成功,否则返回FALSE.若函数内部出错则产生异常.
    BOOL CanRestart( ) const; //若支持Requery则返回TRUE
    BOOL IsOpen( ) const; //若记录集已建立则返回TRUE
       CRecordset类有两个公共成员m_strFilter和m_strSort用来设置对记录的过滤和排序.在调用Open或Requery 前,如果在这两个成员中指定了过滤或排序,那么Open和Requery将按这两个成员指定的过滤和排序来查询源.
    成员m_strFilter用于指定过滤器.m_strFilter实际上包含了SQL的WHERE子句的内容,但它不含WHERE关键字.使用m_strFilter的一个例子为:
    m_pSet->m_strFilter=“CourseID=‘MATH101’”; //只选择CourseID为MATH101的记录
    if(m_pSet->Open(CRecordset::snapshot, “Section”))
    . . . . . .
      成员m_strSort用于指定排序.m_strSort实际上包含了ORDER BY子句的内容,但它不含ORDER BY关键字.m_strSort的一个例子为
    m_pSet->m_strSort=“CourseID DESC”; //按CourseID的降序排列记录
    m_pSet->Open();
    . . . . . .
      事实上,Open函数在构造SELECT语句时,会把m_strFilter和m_strSort的内容放入SELECT语句的WHERE和ORDER BY子句中.如果在Open的lpszSQL参数中已包括了WHERE和ORDER BY子句,那么m_strFilter和m_strSort必需为空.
      调用无参数成员函数Close可以关闭记录集.在调用了Close函数后,程序可以再次调用Open建立新的记录集.CRecordset的析构函数会调用Close函数,所以当删除CRecordset对象时记录集也随之关闭。
    10.5.5 滚动记录
      CRecordset了几个成员函数用来在记录集中滚动,如下所示.当用这些函数滚动到一个新记录时,框架会自动地把新记录的内容拷贝到域成员中.
    void MoveNext( ); //前进一个记录
    void MovePrev( ); //后退一个记录
    void MoveFirst( ); //滚动到记录集中的第一个记录
    void MoveLast( ); //滚动到记录集中的最后一个记录
    void SetAbsolutePosition( long nRows );
    该函数用于滚动到由参数nRows指定的绝对位置处.若nRows为负数,则从后往前滚动.例如,当nRows为-1时,函数就滚动到记录集的末尾.注意,该函数不会跳过被删除的记录.
    virtual void Move( long nRows, WORD wFetchType = SQL_FETCH_RELATIVE );
    该函数功能强大.通过将wFetchType参数指定为SQL_FETCH_NEXT、SQL_FETCH_PRIOR、 SQL_FETCH_FIRST、SQL_FETCH_LAST和SQL_FETCH_ABSOLUTE,可以完成上面五个函数的功能.若 wFetchType为SQL_FETCH_RELATIVE,那么将相对当前记录移动,若nRows为正数,则向前移动,若nRows为负数,则向后移 动.
     
      如果在建立记录集时选择了CRecordset::skipDeletedRecords选项,那么除了SetAbsolutePosition外,在滚动记录时将跳过被删除的记录,这一点对象FoxPro这样的库十分重要.
      如果记录集是空的,那么调用上述函数将产生异常.另外,必须保证滚动没有超出记录集的边界.调用IsEOF和IsBOF可以进行这方面的检测.
     
    BOOL IsEOF( ) const;
    如果记录集为空或滚动过了最后一个记录,那么函数返回TRUE,否则返回FALSE.
    BOOL IsBOF( ) const;
    如果记录集为空或滚动过了第一个记录,那么函数返回TRUE,否则返回FALSE.

    浏览 192赞 148时间 2023-12-15
  • 小宇宙可劲儿造

    直接用mysql c api的函数 你自己可以用C++封装一下,注意下:可以考虑封装成一个单例类

    浏览 208赞 63时间 2023-05-14

MFC操作数据库有关的类

我知道CDatabase和CRecordSet两个类,然后还有插入和删除和更新要用什么类来操作?