关于解决VS2008ODBC连接MySQL时“绑定所有列“程序崩溃问题

2012年5月20更新:

1. 连Oracle没有这个问题,修改了标题

2.可以使用VC6生成这些东西,不过和VS2008生成的有一些不同。

==============


这两天做数据库实验,VS2008连接MySQL数据库的时候,或者添加类的时候,每次勾选“绑定所有列”都会导致VS2008崩溃,上网一番搜索也没找到什么合适的解决方式。找到的一些文章都是建议手工绑定。



虽然我用的表不超过十个,每个表里的属性也不超过十个,不过总觉得手工去建立一个一个CRecordSet的派生类,再自己在*.h添加变量,在*.cpp添加诸如“RFX_Text(pFX, _T("location"), m_location);”这样的句子实在是太麻烦了……


于是自己写了一个小小的代码生成器来完成这项工作。其实思路很简单,就是读取*.sql文件里的create table部分,参照VS2008 Class Wizard自动生成对应的*.h和*.cpp,生成对应的*.h和*.cpp文件。分别为table对应的CRecordSet的派生类。之后把这些文件都拷贝到VS2008工程的文件夹里,添加到项目中就可以了。


生成器是按照自己写*.sql的习惯来写的,主要是方便自己使用,所以对sql文件有做了几个小限制:
1. 使用生成代码器前把create table替换成createtable
2. table名字不包括“XXXXXXXX”,因为这个作为占位符放在sample.h和sample.cpp中供复制文件时替换
3. 目前只支持varchar和int类型,因为我暂时只需要这两个,不过扩展起来很方便

4. 习惯性写法“create table tablename( ...”中tablename后加一个括号,然后换行,所以代码生成器中直接去掉括号得到tablename


要手工改一下*.cpp里初始化部分的n_Fields……


如果发现新添加的这些类没有基类型,手工用Class Wizard添加一个CRecordSet的派生类再删掉就可以了。


代码草草加了一些注释,贴上来吧。

/*
CRecordSet派生类产生器
团子 2012年4月20日
sql文件要求:
处理前先把"create table"换成createtable
table名后换行
暂时只处理varchar和int类型,别的有需要再加
假设table不会叫"XXXXXXXX"
*/

#include <string>
#include <iostream>
#include <fstream>
using namespace std;

const string output_dir="res\\";    //输出文件夹
const string sqlfilename="lab2_gen.sql";    //*.sql文件
const string suffix="set";          //类名=C+tablename+suffix

string tablename;                   //当前处理的table的名字+suffix

void copytofile(ofstream &dst, const char* filename)
{
    ifstream src(filename);
    if (!src.is_open())
    {
        printf("%s 未找到!\n", filename);
        return;
    }
    int pos;
    string tmp;
    while (getline(src, tmp))
    {
        while ((pos=tmp.find("XXXXXXXX", 0))!=string::npos)
        {
            tmp.replace(pos, 8, tablename.c_str());
        }
        dst<<tmp<<endl;
    }
    src.close();
}

int main()
{
    string str[2];
    ofstream res_h, res_cpp;

    freopen(sqlfilename.c_str(), "r", stdin);

    int now=0, pre=1;
    str[pre]="";

    while (cin>>str[now])
    {
        const char* strpre=str[pre].c_str();
        const char* strnow=str[now].c_str();
        if (str[pre].find("createtable", 0)==0)
        {
            str[now].replace(str[now].find("(", 0),1,"");  //如果习惯性写法中table名之后连着括号
            tablename=str[now]+"set";
            string hname=output_dir+tablename+".h";
            string cppname=output_dir+tablename+".cpp";
            printf("build %s %s\n", hname.c_str(), cppname.c_str());
            res_h.open(hname.c_str(), ios::out);
            res_cpp.open(cppname.c_str(), ios::out);
            if (!res_h.is_open() || !res_cpp.is_open())
            {
                printf("输出文件打开失败!\n");
                return 0;
            }
            copytofile(res_h, "sample1.h");
            copytofile(res_cpp, "sample1.cpp");
        }
        if (str[now].find("varchar", 0)==0)
        {
            //变量名以m_开头
            res_h<<"\tCString m_"<<str[pre]<<";"<<endl;
            res_cpp<<"\tRFX_Text(pFX, _T(\""<<str[pre]<<"\"), m_"<<str[pre]<<");"<<endl;
        }
        else if (str[now].find("int", 0)==0)
        {
            //变量名以m_开头
            res_h<<"\tint m_"<<str[pre]<<";"<<endl;
            res_cpp<<"\tRFX_Int(pFX, _T(\""<<str[pre]<<"\"), m_"<<str[pre]<<");"<<endl;
        }
        //else if ... 如果要添加对更多类型的支持,这里可以相应扩展
        if (str[now].find(");", 0)==0)
        {
            copytofile(res_h, "sample2.h");
            copytofile(res_cpp, "sample2.cpp");
            res_h.close();
            res_cpp.close();
        }
        now=1-now;
        pre=1-pre;
    }
    return 0;
}


sample.h和sample.cpp是VS2008 Class Wizard自动生成的CRecordSet的派生类对应的文件修改而来的。拆成两部分,中间部分正好是用来添加变量或者是RFX_Text之类的。

sample1.h

// XXXXXXXX.h : CXXXXXXXX 的声明

#pragma once

// 由团子的code_gen生成~

class CXXXXXXXX : public CRecordset
{
public:
	CXXXXXXXX(CDatabase* pDatabase = NULL);
	DECLARE_DYNAMIC(CXXXXXXXX);

// 字段/参数数据


sample1.cpp

// XXXXXXXX.h : CXXXXXXXX 类的实现

// CXXXXXXXX 实现

// 由团子的code_gen生成~

#include "stdafx.h"
#include "XXXXXXXX.h"
IMPLEMENT_DYNAMIC(CXXXXXXXX, CRecordset)

CXXXXXXXX::CXXXXXXXX(CDatabase* pdb)
	: CRecordset(pdb)
{
	m_nFields = 0;
	m_nDefaultType = dynaset;
}

CString CXXXXXXXX::GetDefaultConnect()
{
	return _T("换掉我");  //换成自己的
}

CString CXXXXXXXX::GetDefaultSQL()
{
	return _T("");
}

void CXXXXXXXX::DoFieldExchange(CFieldExchange* pFX)
{
	pFX->SetFieldType(CFieldExchange::outputColumn);


sample2.h

// 以下字符串类型(如果存在)反映数据库字段(ANSI 数据类型的 CStringA 和 Unicode
// 数据类型的 CStringW)的实际数据类型。
//  这是为防止 ODBC 驱动程序执行可能
// 不必要的转换。如果希望,可以将这些成员更改为
// CString 类型,ODBC 驱动程序将执行所有必要的转换。
// (注意: 必须使用 3.5 版或更高版本的 ODBC 驱动程序
// 以同时支持 Unicode 和这些转换)。


// 重写
	// 向导生成的虚函数重写
	public:
	virtual CString GetDefaultConnect();	// 默认连接字符串
	virtual CString GetDefaultSQL(); 	// 记录集的默认 SQL
	virtual void DoFieldExchange(CFieldExchange* pFX);	// RFX 支持

// 实现
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

};



sample2.cpp

}
/
// CXXXXXXXX Õï¶Ï

#ifdef _DEBUG
void CXXXXXXXX::AssertValid() const
{
	CRecordset::AssertValid();
}

void CXXXXXXXX::Dump(CDumpContext& dc) const
{
	CRecordset::Dump(dc);
}
#endif //_DEBUG



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值