您的位置:首页 > 数据库 > MySQL

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

2012-04-20 13:55 531 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐