如何用CRecordSet类进行多次数据库操作,Open后再查询怎么办?

wxlran 2004-12-29 02:07:10
某处看到的:“使用过CRecordSet::Open()函数,再次查询时就可以应用CRecordSet::Requery() 函数。CRecordSet 类对象的初始化,缺省数据源由GetDefaultConnect()函数获得,
!!也可以提供你所需要的SQL 语句,并以它来调用CRecordSet::Open() 函数!!(就是不明白自定义的语句可用于多次查询么?我做的时候怎么出错了?)
查询过程中也可以利用CRecordSet 的成员变量m_strFilter 和m_strSort 来执行条件查询和结果排序。”

CPersonSet m_recordset(&m_database);
CString searchid;
searchid.Format("ID=%d",i);
strSQL.Format("select * from person where %s",searchid);

//初始查询操作--》
m_recordset.m_strFilter=searchid;//利用成员变量来操作的(A)两句
m_recordset.Open(AFX_DB_USE_DEFAULT_TYPE,NULL);

//m_recordset.Open(AFX_DB_USE_DEFAULT_TYPE,strSQL);//××××利用自定义sql语句来操作的语句(B)

m_recordset.m_strFilter="NAME='vfcgf'";
//不关闭m_recordset做连续的第2次查询,
m_recordset.Requery();
AfxMessageBox("requery success");

问题1:
用A处的代码没有问题,但是A换成B的话Requery();就出错“语法错误(操作符丢失)在查询表达式‘ID=1 WHERE NAME=‘vfcgf’’中”,为什么换了后的效果是这样呢?

问题2:
我是用CLASS WIZARD添加的CRecordset继承类,关联数据源时选择的是snapshot,
我在程序里这样m_recordset->Open(CRecordset::dynaset,str_SQL,CRecordset::readOnly);
会提示我说提示说:“ODBC驱动程序不支持动态记录集”
这又是为什么呢?我访问的是ACCESS数据源。
我又用class wizard里UpdateColumon更新程序里的CPersonSet的设置,选dynaset的RADIO钮,可是点确定关闭class wizard后再ctrl+w,再操作一下看却仍是snapshot被选中,我到CPersonSet代码里把type的参数改成dynaset。可是还是那个提示,郁闷。。。
...全文
263 点赞 收藏 12
写回复
12 条回复
yiyouyou 2004年12月29日
我跟踪了下,出错的位置在//————————标识处
CPassSet* m_paset = new CPassSet(&m_database);
CString sql;
sql.Format("select * from password where PASSWORD='%s'",m_edit_pass);
m_paset->Open(CRecordset::dynaset,sql,CRecordset::dynaset);
if(m_paset->GetRecordCount()==0)
{
if(counts<3)
{
AfxMessageBox("口令错误!");
counts++;
m_edit_pass.Empty();
m_ctrpass.SetFocus();
UpdateData(FALSE);
}
else
{
MessageBox("你无权使用此系统!","警告",MB_OK|MB_ICONHAND);
m_database.Close();
CDialog::OnOK();
}
}
else
{
//密码正确的话关闭当前数据库连接并弹出主对话框-----》
m_database.Close();
CMainDlg maindlg;
maindlg.m_database.Open(_T("addresslist"));//是不是这里导致后面出问题???
KillTimer(0);
CDialog::OnOK();
maindlg.DoModal();//—————运行到这里时出错:“ODBC驱动程序不支持动态记录”
}
我也不是太清楚,maindlg.m_database.Open(_T("addresslist"));//是不是这里导致后面出问题???


回复 点赞
wxlran 2004年12月29日
哦,明白了,只能按它的规矩楼。

谢谢大家。
现在就剩下dynaset的问题了。我又做了个小的DEMO,用CLASS WIZARD产生记录集的类。
CPersonSet::CPersonSet(CDatabase* pdb)
: CRecordset(pdb)
{ //{{AFX_FIELD_INIT(CPersonSet)
m_ID = 0;
m_NAME = _T("");
m_nFields = 2;
//}}AFX_FIELD_INIT
m_nDefaultType = snapshot;//这里不一样
}
CMYSet::CMYSet(CDatabase* pdb)
: CRecordset(pdb)
{
//{{AFX_FIELD_INIT(CMYSet)
m_PASSWORD = _T("");
m_nFields = 1;
//}}AFX_FIELD_INIT
m_nDefaultType = dynaset;//这里不一样
}
Open的时候用
CMYSet *m_set=new CMYSet(&m_database);
m_set->Open(CRecordset::dynaset,sql,CRecordset::dynaset);

CPersonSet *m_p=new CPersonSet(&m_database);
m_p->Open(CRecordset::dynaset,sql2,CRecordset::dynaset);
都没有出提示:“ODBC驱动程序不支持动态记录集”。
郁闷啊,真不知道我那个这里出问题程序为什么
从Open(AFX_DB_USE_DEFAULT_TYPE,sql);
换成Open(CRecordset::dynaset,sql,CRecordset::dynaset);就出问题???
既然继承类的构造函数里有参数设置m_nDefaultType = dynaset;
那么用AFX_DB_USE_DEFAULT_TYPE和用CRecordset::dynaset不是应该一样么?
回复 点赞
wxlran 2004年12月29日
TO: zhangqu_980371(能坚持一辈子的东西太少)
那岂不是说开始的时候不能设定条件查询?
回复 点赞
wxlran 2004年12月29日
TO: laiyiling(陌生人)
1). 我摘了循环里的一段代码而已,
int =1;if(...)
{ CString searchid;
searchid.Format("ID=%d",i);
strSQL.Format("select * from person where %s",searchid);
这样SQL语句就是"select * from person where ID=1".
是为了每次循环针对i变换查询条件。
2).m_recordset->Open(CRecordset::dynaset,str_SQL,CRecordset::dynaset);这样改了后还是不行,是不是和我用CLASS WIZARD创建CRecordSet的关联有关?我看CLASS WIZARD里member variable数据库数据下面有这么一句“binding varchar column to CString field”??

TO: zhangqu_980371(能坚持一辈子的东西太少)
我就是看这个学的,你能按我想要的目的给个正确的用法么??
就是开始OPEN的时候用自定义的SQL语句,后面通过改过滤参数再REQUERY?我只有用默认的语句才不出错。

再说明一下,我贴的代码是可以运行的,就是按我说的用注释掉的B句换去A才出现的问题。
//这样可以-》
m_recordset.m_strFilter=searchid;//利用成员变量来操作的(A)两句
m_recordset.Open(AFX_DB_USE_DEFAULT_TYPE,NULL);//用默认语句
m_recordset.m_strFilter="NAME='vfcgf'";
//不关闭m_recordset做连续的第2次查询,
m_recordset.Requery();

//这样就不行-》
m_recordset.Open(AFX_DB_USE_DEFAULT_TYPE,strSQL);//××××利用自定义sql语句来操作的语句(B)
m_recordset.m_strFilter="NAME='vfcgf'";
//不关闭m_recordset做连续的第2次查询,
m_recordset.Requery();

回复 点赞
zhangqu_980371 2004年12月29日
简单一点说就是在你的open()里的strSQL,不要带where条件。就可以用requery了。
回复 点赞
zhangqu_980371 2004年12月29日
你的requery()函数用的不对。
参考以下文章:
3.22 查询记录

查询记录使用CRecordSet::Open()和 CRecordSet::Requery()成员函数。在使用CRecordSet类对象之前,必须使用 CRecordSet::Open()函数来获得有效的记录集。一旦已经使用过CRecordSet::Open() 函数,再次查询时就可以应用CRecordSet::Requery()函数。在调 用CRecordSet::Open()函数时,如果已经将一个已经打开的CDatabase 对象指针传给CRecordSet类对象的m_pDatabase成员变量,则使 用该数据库对象建立ODBC连接;否则如果m_pDatabase为空指 针,就新建一个CDatabase类对象并使其与缺省的数据源 相连,然后进行CRecordSet类对象的初始化。缺省数据源 由GetDefaultConnect()函数获得。你也可以提供你所需要的SQL 语句,并以它来调用CRecordSet::Open()函数,例如:

m_Set.Open(AFX_DATABASE_USE_DEFAULT,strSQL);

如果没有指定参数,程序则使 用缺省的SQL语句,即对在GetDefaultSQL()函数中指定的SQL语 句进行操作: 

CString CTestRecordSet::GetDefaultSQL()

{return _T("[BasicData],[MainSize]");}

对于GetDefaultSQL()函数返回的表名, 对应的缺省操作是SELECT语句,即:

SELECT * FROM BasicData,MainSize 


查询过程中也可以利用CRecordSet的 成员变量m_strFilter和m_strSort来执行条件查询和结果排序。m_strFilter 为过滤字符串,存放着SQL语句中WHERE后的条件串;m_strSort 为排序字符串,存放着SQL语句中ORDERBY后的字符串。 如:

m_Set.m_strFilter="TYPE='电动机'";

m_Set.m_strSort="VOLTAGE";

m_Set.Requery();

对应的SQL语句为:

SELECT * FROM BasicData,MainSize

WHERE TYPE='电动机'

ORDER BY VOLTAGE


除了直接赋值给m_strFilter以外,还 可以使用参数化。利用参数化可以更直观,更方便地 完成条件查询任务。使用参数化的步骤如下: 

(1).声明参变量: 

Cstring p1;

Float p2;

(2).在构造函数中初始化参变量

p1=_T("");

p2=0.0f;

m_nParams=2;

(3).将参变量与对应列绑定

pFX->SetFieldType(CFieldExchange::param)

RFX_Text(pFX,_T("P1"),p1);

RFX_Single(pFX,_T("P2"),p2);

完成以上步骤之后就可以利用参变量进行条件查询了:

m_pSet->m_strFilter="TYPE=?ANDVOLTAGE=?";

m_pSet->p1="电动机";

m_pSet->p2=60.0;

m_pSet->Requery();


参变量的值按绑定的顺序替换 查询字串中的“?”适配符。

如果查询的结果是多条记录的 话,可以用CRecordSet类的函数Move(),MoveNext(),MovePrev(),MoveFirst() 和MoveLast()来移动光标。

回复 点赞
xzyong 2004年12月29日
virtual BOOL Open(
UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE,
LPCTSTR lpszSQL = NULL,
DWORD dwOptions = none
);
Parameters
nOpenType
Accept the default value, AFX_DB_USE_DEFAULT_TYPE, or use one of the following values from the enum OpenType:
CRecordset::dynaset A recordset with bi-directional scrolling. The membership and ordering of the records are determined when the recordset is opened, but changes made by other users to the data values are visible following a fetch operation. Dynasets are also known as keyset-driven recordsets.
CRecordset::snapshot A static recordset with bi-directional scrolling. The membership and ordering of the records are determined when the recordset is opened; the data values are determined when the records are fetched. Changes made by other users are not visible until the recordset is closed and then reopened.
CRecordset::dynamic A recordset with bi-directional scrolling. Changes made by other users to the membership, ordering, and data values are visible following a fetch operation. Note that many ODBC drivers do not support this type of recordset.
CRecordset::forwardOnly


试试把AFX_DB_USE_DEFAULT_TYPE改为CRecordset::dynaset或CRecordset::snapshot
回复 点赞
Kudeet 2004年12月29日
1
strSQL.Format("select * from person where %s",searchid);
//这个SQL语句明显有问题,你查询的条件列在哪里呢?

2
m_recordset->Open(CRecordset::dynaset,str_SQL,CRecordset::dynaset);
回复 点赞
zhangqu_980371 2004年12月29日
呵呵,已经发过去了!
回复 点赞
wxlran 2004年12月29日

我的我之前用Open(AFX_DB_USE_DEFAULT_TYPE,sql);的方式的时候
m_nDefaultType = snapshot;
代码里有这样Open(_T("addresslist"));的方式没问题。addresslist是我的数据源名称。

现在我理解的是这样打开和动态打开产生矛盾把,对把?

谢谢!!大家,揭贴了。
我的信箱wxlran@tom.com
回复 点赞
zhangqu_980371 2004年12月29日
还是留下email吧。
回复 点赞
zhangqu_980371 2004年12月29日
Open(_T("addresslist"));//是不是这里导致后面出问题???

当然出问题啊。这个open里面是数据源连接字符串,你的是”addresslist“
又怎么能打开数据库啊。

呵呵,手头刚好有个跟你的要求一模一样的例子,要的话发给你好。然后你分析一下好点。
QQ:82591254
回复 点赞
发动态
发帖子
数据库
创建于2007-09-28

3443

社区成员

3.9w+

社区内容

VC/MFC 数据库
社区公告
暂无公告