荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Peter (小飞侠), 信区: Program
标  题: VC4.0下ODBC参数化 记录集与动态绑定方法的实现编程?
发信站: BBS 荔园晨风站 (Wed Jan 27 17:43:06 1999), 转信


运用参数化记录集与动态绑定技术是ODBC应用程序中提高程序运行
效率的常用方法。与用C语言直接调用ODBC函数的做法相比,VC4.0及
其所包含的MFC基本类库提供了方便地实现上述方法的手段。下面将
具体介绍VC4.0中参数化记录集与动态绑定方法的实现。
    参数化记录集与动态绑定
    在利用ODBC开发Client/Server应用程序的过程中,程序员必然会
遇到这样的问题:如何快速高效执行查询操作,既要充分利用Client/S
erver结构的优点,又要尽量少占用数据库服务器的资源。在VC4.0中
常用的方法是先根据表的结构利用Class Wizard生成一个对应表的CR
ecordSet的派生类,然后根据不同的查询条件修改筛选字符串类的数
据成员m_strField的值,并调用Requery()成员函数以得到满足指定条
件的记录集。但是,通过分析程序的执行过程及MFC的源代码可知:在
每次建立一个新的筛选字符串后,CRecordSet类根据所对应的表的结
构生成一个SQL语句,并经ODBC驱动程序提交给服务器执行。服务器在
接到请求以后首先要对此SQL语句进行语法分析以及优化,将SQL语句
所定义的操作分解,然后提交给服务器数据库引擎执行,并将最终结果
返回给客户。这样当筛选字符串具有相同的形式而仅仅只有筛选参数
取值不同时,每次进行这样相同的操作将严重浪费服务器的资源。
    针对上述情况ODBC接口提供了参数化记录集的功能,即可以生成
一个满足通过一些参数给定查询条件的记录集,直接修改这些参数就
可以得到满足不同条件的记录集。这样由于参数化记录集中参数直接
传递给数据库引擎,避免了每次对相同的SQL语句进行上述操作,因而
大大提高了SQL语句的执行效率,特别是针对重复的、结构相似的查询
,这种提高更显著。而动态绑定技术则允许应用程序根据不同的条件
绑定不同的数据项,这样可以在程序中利用一个CRecordSet的实例分
别存储多个表中的数据或者操作用户在程序运行中生成的新表(因为
利用Class Wizard生成CRecordSet的派生类时,必须先有确定的表的
结构)。这对于减少程序占用机器资源以及提高程序的灵活性具有重
要意义。
    参数化记录集的实现
    下面以一个学生学籍表为例,通过生成一个将学生学号作为参数
的记录集来说明VC4.0中参数化记录集的实现。该表的结构如下:
表1
    操作步骤如下:

    1.利用VC4.0中的Class Wizard工具创建对应于Student Table的
CRecordSet类的派生类CStudentSet。

    2.在CStudentSet的头文件中为该类加入一个公有的CString类的
数据成员m_strStuden t_Param,注意此数据成员必须加在一对AFX_FI
ELD注释之外。
    //在一对AFX_FIELD注释之中定义的变量即被绑定列对应的变量

    //{{AFX-FIELD(CStudentSet,CRecordSet)
      CString  m_Student_Name;
      CString m_Student_NO;
      CString m_Home_Address;
      CString m_Telephone_NO;
      CString m_Home_Zip;
    //}}AFX_FIELD
    //被绑定参数列对应的变量
       CString m_strStudent_Param;

    3.把新的成员变量加到DoField Exchange方法中,参数正是通过
该方法传递到驱动程序中去的。在把参数增加到DoFieldExchange方
法之前,必须先调用SetFieldType函数表明后面的字段是参数值。
    void CStudentSet::DoFieldExchange(CFieldExchange * pFX)
    {
    //{{AFX_FIELD_MAP(CStudentSet)
    pFX->SetFieldType(CFieldExchange::outputColumn);
        //说明绑定列
    RFX->Text(pFX,_T("[Student_Name]"),m_Student_Name);
    RFX->Text(pFX,_T("Student_NO"),m_Student_NO);
    RFX->Text(pFX,_T("[Home_Address〗"),m_Home_Address);
    RFX->Text(pFX,_T("[Telephone_NO〗"),m_Telephone_NO);
    RFX->Text(pFX,_T("[Home_Zip〗"),m_Home_Zip);
    //}}AFX_FIELD_MAP
    pFX->SetFieldType(CFieldExchange::param);
    //说明绑定参数
    RFX->Text(pFX,_T("Studnet-NO"),m_strStudent_Param);
    }

    4.建立参数化筛选字符串,在构造函数中将CStudentSet中从CRec
ordSet继承的数据成员m_strField初始化成包含未知参数的形式;同
时初始化参数和m_nParam。
    CStudentSet::CStudentSet(CDatabase * pDb):CRecordSet(m_p
Db)
    {
      //参数初始化
       //{{AFX_FIELD_INIT(CWhiteboardSet)
    m_Student_Name=_T("");
    m_Student_NO=_T("");
    m_Home_Address=_T("");
    m_Telephone_NO=_T("");
    m_Home_Zip=_T("");
    m_nFields=5;//绑定列数目
       //}}AFX_FIELD_INIT
       m_strStudent_Param=_T("");
       m_nParams=1;//参数数目
       m_strFilter="Student-NO=?";
    }
    其中"?"即代表参数所在的位置,在包含多个参数的情鱿?ODBC
引擎将按DoFieldExcha nge方法中参数出现的顺序替换m_strField中
的问号。m_nParam的值必须与参数的实际个数相等,否则将引起一些
难以觉察的错误。
    这样,每次根据学生学号来查找学生信息时,只须简单地为m_strS
tudent_Param赋值,并调用Requery()则可得到给定学号的学生信息。

    动态绑定的实现
    我们仍以Student Table为例,假设我们现在根据用户的选择只须
要绑定Student_NO列和其它三列中的某一列或某几列。
    首先,我们在CStudentSet中加入一个CStringList成员变量和一
个CObList成员变量,其中CStringList用于存放字段名,CObList用于
存放与CStringList字段名对应的变量的指针。
    其次,修改DoFieldExchange方法。
    注意在调用Requery()以前必须修改m_nField的值:
        m_nField=m_Column_List.GetCount();
    这样,通过往m_Column_List和m_Storage_List中成对地填入字段
名和对应的变量名,即可实现动态绑定。
    具有动态绑定特性的CStudentSet类的详细结构及实现如下:
    // studentSet.h  CStudentSet类头文件
    class CStudentSet:public CRecordset
    {
    public:
    CStudentSet(CDatabase* pDatabase=NULL);
    DECLARE_DYNAMIC(CStudentSet)
    //设置绑定参数
    //{{AFX_FIELD(CStudentSet,CRecordset)
    CString m_Student_Name;
    CString m_Student_NO;
    CString m_Home_Address;
    CString m_Telephone_NO;
    CString m_Home_Zip;
    //}}AFX_FIELD
    //添加存储动态绑定对象的链表
    public:
       CStringList  m_Column_List;
       CObList   m_Storage_List;
    //{{AFX_VIRTUAL(CStudentSet)
    public:
    virtual CString GetDefultConnect();
        // Default connection string
    virtual CString GetDefaultSQL();
        //default SQL for Recordset
    virtual void DoFieldExchange(CFieldExchange* pFX);
        //RFX support
    //}}AFX_VIRTUAL
    #ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext & dc) const;
    #endif
    };
        // studentSet.cpp  CStudentSet 类CPP文件
    #include "stdafx.h"
    #include "student.h"
    #include "studentSet.h"
        #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE〖〗=--FILE--_;
    #endif
        IMPLEMENT_DYNAMIC(CStudentSet,CRecordset)
    CStudentSet::CStudentSet(CDatabase* pdb): CRecordset(pdb
)
    {   //参数初始化
    //{{AFX_FIELD_INIT(CStudentSet)
    m_Student_Name=_T("");
    m_Student_NO=_T("");
    m_Home_Address=_T("");
    m_Telephone_NO=_T("");
    m_Home_Zip=_T("");
    m_nFields=5;
    //}}AFX_FIELD_INIT
    m_nDefaultType=snapshot;
    }
    CString CStudentSet::GetDefaultConnect()
    {
    return _T("ODBC;DSN=Student");
    }
    CString CStudentSet::GetDefaultSQL()
    {
    return _T("Student");
    }
       //修改后的DoFieldExchange方法函数
    void CStudentSet::DoFieldExchange(CFieldExchange* pFX)
    {
    //{{AFX_FIELD_MAP(CStudentSet)
    pFX->SetFieldType(CFieldExchange::outputColumn);
    POSITION  pos=m_Column_List.GetHeadPosition();
    while(pos!=NULL)
    RFX_Text(pFx,m_Column_List.GetNext(pos),
    *m_Storage_List.GetNext(pos));
    //}}AFX_FIELD_MAP
    }
        //CStudentSet diagnostics
    #ifdef _DEBUG
    void CStudentSet::AssertValid() const
    {
    CRecordset::AssertValid();
    }
        void CStudentSet::Dump(CDumpContext& dc) const
    {
    CRecordset::Dump(dc);
    }
    #endif  //_DEBUG

--
※ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: 192.168.1.3]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店