4

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

MFC 的 CDatabase 不再使用它(而它是 VS2010 和 MFC 早期版本的默认设置),而是使用 SQL_CUR_USE_DRIVER。

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

问题

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

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


更新:查看各种选项,似乎游标库已从 VS2012 的 ODBC 库中删除。结合 Jet 不能正确支持位置更新 (2) 的事实,它使“快照”模式无法使用。只要基础表具有主键,它似乎就支持“动态集”。无键表与“动态集”模式 (3) 不兼容。所以 - 我可以坚持使用 VS 2010,或者我可以更改我的表格以包含自动编号或类似的东西,以确保 pkey 可用,以便我可以对记录集使用动态集模式。


(1) 例如,我们应该为 CRecordset 使用不同的开放类型吗?我们目前使用 CRecordset::snapshot。但我从来没有真正理解快照、动态、动态集的各种模式。一组快速的“尝试每个”未能获得到我们的访问数据库的工作可更新接口......
(2)它在最初查询时声称,但随后返回它之前声称支持的所有并发模式的错误
(3) “动态”也出来了,因为 Jet 根本不支持它(从我的测试中可以看出)。

4

3 回答 3

4

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

MyCDatabase.h

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

MyCDatabase.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 的黑客版本中覆盖它。

另请注意,这只是一个 hack,但它似乎有效。请测试您的所有代码以确保它按预期工作,但到目前为止它对我来说工作正常。

于 2013-02-21T22:10:30.557 回答
2

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

对于 ODBC 到 Access 数据库,使用 CDatabase mydb 连接;mydb.OpenEx(.., 0),这样你就要求系统不要加载游标库。

然后对于记录集,使用 dynaset CMyRecordset myrs; myrs.Open(CRecordset::dynaset, ...)。

最后,您必须确保您的表有一个主键才能使用动态集(keysets)。

于 2012-10-04T17:41:19.080 回答
0

派生CDatabase并覆盖OpenEx。在您的派生类CMyDatabase中,替换对 to 的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所有查询。

于 2012-10-04T06:37:42.110 回答