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

帅比萌擦擦* 提交于 2019-12-01 09:10:53

I found a solution that appears to work. I overrode OpenEx the exact same way VS 2012 has it because we need that to call the child version of AllocConnect since it is not virtual in the parent. I also overrode AllocConnect as mentioned. In the derived version of CDatabase, try the following code:

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;
}
}

Please note that you do not want to pass in useCursorLab to OpenEx at first, you need to override it in the hacked version of AllocConnect.

Also note that this is just a hack but it appears to work. Please test all your code to be sure it works as expected but so far it works OK for me.

If anyone else runs into this issue, here's what seems to be the answer:

For ODBC to an Access database, connect using CDatabase mydb; mydb.OpenEx(.., 0), so that you ask the system not to load the cursor library.

Then for the recordsets, use dynaset CMyRecordset myrs; myrs.Open(CRecordset::dynaset, ...).

Finally, you must make sure that your tables have a primary key in order to use dynasets (keysets).

Derive CDatabase and override OpenEx. In your derived class CMyDatabase, replace the call to AllocConnect to MyAllocConnect. Obviously, your MyAllocConnect function should call SQLSetConnectOption with the desired parameter:

// 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;
}

Then use your CMyDatabase class instead of CDatabase for all your queries.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!