在用MFC数据库类CDatabase和CRecordset类声明的对像无法对打开的数据集进行编辑、添加、删除。偶然间让我碰到个这样的问题让我费了不少精神,不知道为什么数据库能正常打开,数据集也正常Open。可是就是没办法进入编辑状态,老是会弹出“记录集只读”的提示。
------------------------------------------------------------------------------------------------------------------------------
CDatabase db;
db.OpenEx (_T"DSN=strtab");
CRecordset m_Set (&db);
m_Set.Open (AFX_DB_USE_DEFAULT_TYPE, _T"select *from strtab");
if (!m_Set.IsOpen ()) AfxMessageBox ("数据集没能打开!");
m_Set.Edit ();
--------------------------------------------------------------------------------------------------------------------------------
检查一下自己的程序,发现不管是声明的CDatabase对像还是通过CRecordset对像打开的记录集都使用的是缺省参数,而在我的记忆中CDatabase::OpenEx()和CRecordset::Open()这两个成员函数的缺省参数打开的记录集和数据库对像都是非只读的。倒底是那里的问题呢?
BOOL CDatabase::OpenEx(LPCTSTR lpszConnectString, DWORD dwOptions)
virtual BOOL Open(UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE,
LPCTSTR lpszSQL = NULL, DWORD dwOptions = none);
我在我的程序中打开数据集的Open()处下了断点并跟踪进去,发现CRecordset对像的m_bUpdatable标志位最初始一直是为TRUE,即可更新状态。随后进入了如下一串令人眼花缭乱的函数调用里,终于找到m_bUpdatable的值在那里被更改,这一切的问题出自那里!
-----------------------------------------------------------------------------------------------------------------------------------------------
BuildSQL(lpszSQL);
if ((m_bUpdatable || m_bAppendable) && !IsRecordsetUpdatable())
if (!IsSQLUpdatable(m_strSQL))
return IsSelectQueryUpdatable(lpszSQL);
lpchTokenFrom = FindSQLToken(strSQL, _afxFrom); //AFX_STATIC_DATA const TCHAR _afxFrom[] = _T(" FROM ");
lpszFoundToken = _tcsstr(lpszFoundToken + nTokenOffset, lpszSQLToken);
--------------------------------------------------------------------------------------------------------------------------------------------------
上面这每一行是跟踪进去的函数,蓝色字是函数名。这些函数是分析传递进来的SQL语句的并进行相应的设置来打开数据集。注意第五行_afxFrom的值是什么!这是MFC定义的一个常量,它的订义在注释那里。问题就在这里了,MFC定义这个常量用来分析SQL语句中是否包含用FROM关键字以及其后的表名,要有这个关键字那么数据集才是以可更新的状态打开的。但是,很明显我的程序中打开数据集用的SQL语句是有这个FROM关键字和表名的。那么我应该得到一个可更新的数据集才对啊,为什么我不能更新呢?仔细看看MFC定义的这个_afxFrom常量,它的值是_T(" FROM ")FROM的前后各有一个空格,因此真相大白了。问题就是我的SQL语句因为要返回所有的字段,就没有给出字段名而是直接用*号表示要返回所有字段,而这个*号紧挨着FROM关键字,所以在最后一行中MFC用_tcsstr()函数在SQL语句中查找_afxFrom,结果是永远也找不到MFC定义的这个两头各有一个空格的FROM关键。_tcsstr()返回一个空指针,接着这些函数一路返回FALSE,这样m_bUpdatable的值就为FALSE,我所打开的数据集也是不可更新数据集。
这样的问题为什么以前没有出现呢?那是因为以前我要不是只返回特定的字段,构造好的SQL语句中的FROM也是同样前后都有空格。就是直接CRecordset::Open()一个参数不带的执行这个Open()函数。这样由MFC自行构造的缺省SQL语句肯定是符合他自己的要求。
实际上,我这样的*号紧挨FROM的SQL语句写法也是很多人的习惯。所以,我相信也有不少的朋友也碰到这样的问题。