CRecordset::snapshot 在 VS2012 中不再起作用 - 还有什么替代方案?

CRecordset::snapshot doesn't work in VS2012 anymore - what's the alternative?

本文关键字:什么 方案 起作用 snapshot VS2012 CRecordset 不再      更新时间:2023-10-16

显然,在VS2012中,SQL_CUR_USE_ODBC已被弃用。[更新:游标库似乎已从VS2012中完全删除]。

MFC的C数据库不再使用它(而它是VS2010和早期版本MFC的默认数据库),而是使用SQL_CUR_use_DRIVER。

不幸的是,SQL_CUR_USE_DRIVER无法与Jet ODBC驱动程序正常工作(我们正在与Access数据库交互)。驱动程序最初声称支持位置操作(但不支持位置更新),但当尝试实际查询数据库时,所有并发模型都会失败,直到MFC库降到与数据库的只读交互(这对我们来说是行不通的)。

问题

  • 这是MS最近试图迫使开发人员远离基于Jet的数据源并迁移到SQL Express(或类似的)吗
  • 我们是否应该使用另一种模式通过VS2012版本的MFC/ODBC与Access数据库进行交互?(1)

另请参阅:http://social.msdn.microsoft.com/Forums/kk/vcmfcatl/thread/acd84294-c2b5-4016-b4d9-8953f337f30c


更新:查看各种选项,光标库似乎已从VS2012的ODBC库中删除。再加上Jet不正确支持位置更新(2),这使得"快照"模式无法使用。只要基础表有主键,它似乎确实支持"dynaset"。无键表与"动态集"模式不兼容(3)。所以-我可以坚持使用VS 2010,或者我可以更改我的表以包括自动编号或类似的内容,以确保pkey可用,这样我就可以对记录集使用dynaset模式。


(1)例如,我们是否应该为CRecordset使用不同的打开类型?我们目前使用CRecordset::snapshot。但我从来没有真正理解过快照、动态、动态集的各种模式。一组快速的"try-each"无法获得访问数据库的可更新接口
(2)它在最初查询时声称支持,但随后返回了以前声称支持的所有并发模式的错误
(3)"动态"也被取消,因为Jet根本不支持它(从我的测试中可以看出)。

我找到了一个似乎有效的解决方案。我以与VS 2012完全相同的方式重写OpenEx,因为我们需要它来调用AllocConnect的子版本,因为它在父版本中不是虚拟的。如前所述,我还覆盖了AllocConnect。在CDatabase的派生版本中,尝试以下代码:

MyC数据库.h

BOOL OpenEx(LPCTSTR lpszConnectString, DWORD dwOptions = 0);
void AllocConnect(DWORD dwOptions);

MyC数据库.cpp

BOOL MyCDatabase::OpenEx(LPCTSTR lpszConnectString, DWORD dwOptions)
{
ENSURE_VALID(this);
ENSURE_ARG(lpszConnectString == NULL || AfxIsValidString(lpszConnectString));
ENSURE_ARG(!(dwOptions & noOdbcDialog && dwOptions & forceOdbcDialog));
// Exclusive access not supported.
ASSERT(!(dwOptions & openExclusive));
m_bUpdatable = !(dwOptions & openReadOnly);
TRY
{
m_strConnect = lpszConnectString;
DATA_BLOB connectBlob;
connectBlob.pbData = (BYTE *)(LPCTSTR)m_strConnect;
connectBlob.cbData = (DWORD)(AtlStrLen(m_strConnect) + 1) * sizeof(TCHAR);
if (CryptProtectData(&connectBlob, NULL, NULL, NULL, NULL, 0, &m_blobConnect))
{
SecureZeroMemory((BYTE *)(LPCTSTR)m_strConnect, m_strConnect.GetLength() * sizeof(TCHAR));
m_strConnect.Empty();
}
// Allocate the HDBC and make connection
AllocConnect(dwOptions);
if(!CDatabase::Connect(dwOptions))
return FALSE;
// Verify support for required functionality and cache info
VerifyConnect();
GetConnectInfo();
}
CATCH_ALL(e)
{
Free();
THROW_LAST();
}
END_CATCH_ALL
return TRUE;
}
void MyCDatabase::AllocConnect(DWORD dwOptions)
{
CDatabase::AllocConnect(dwOptions);
dwOptions = dwOptions | CDatabase::useCursorLib;
// Turn on cursor lib support
if (dwOptions & useCursorLib)
{
::SQLSetConnectAttr(m_hdbc, SQL_ATTR_ODBC_CURSORS, (SQLPOINTER)SQL_CUR_USE_ODBC, 0);
// With cursor library added records immediately in result set
m_bIncRecordCountOnAdd = TRUE;
}
}

请注意,您一开始不想将useCursorLab传递给OpenEx,您需要在AllocConnect的黑客版本中覆盖它。

还要注意,这只是一个黑客,但它似乎是工作。请测试你的所有代码,以确保它按预期工作,但到目前为止,它对我来说还可以。

如果其他人遇到这个问题,答案似乎是:

对于ODBC到Access数据库,请使用CDatabase-mydb进行连接;mydb。OpenEx(..,0),这样您就可以要求系统不要加载光标库。

然后,对于记录集,使用dynaset CMyRecordset myrs;myrs。打开(CRecordset::dynaset,…)。

最后,您必须确保您的表具有主键,以便使用动态集(keyset)。

派生CD数据库并覆盖OpenEx。在派生类CMyDatabase中,将对AllocConnect的调用替换为MyAllocConnect。显然,MyAllocConnect函数应该使用所需的参数调用SQLSetConnectOption:

// Turn on cursor lib support
if (dwOptions & useCursorLib)
{
AFX_SQL_SYNC(::SQLSetConnectOption(m_hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_ODBC));
// With cursor library added records immediately in result set
m_bIncRecordCountOnAdd = TRUE;
}

然后对所有查询使用CMyDatabase类而不是CDatabase