使用 ADO Recordset::Update() 或 UpdateBatch() 時拋出「無法更新」錯誤,常見於批量新增、游標類型不匹配、欄位資料類型衝突等場景。
將批量操作包裝在事務中,任何單條失敗自動回滾,避免部分提交導致資料不一致。
try {
m_pConnection->BeginTrans();
for (int i = 0; i < nCount; ++i) {
m_pRecordset->AddNew();
m_pRecordset->PutCollect("Field1", _variant_t(strVal));
m_pRecordset->PutCollect("Field2", _variant_t(dateVal));
// ... 其他欄位
m_pRecordset->Update(); // 逐條 Update 或最後 UpdateBatch
}
m_pConnection->CommitTrans();
}
catch (_com_error& e) {
m_pConnection->RollbackTrans();
// 記錄錯誤
}
注意:事務不宜過長,避免鎖升級導致死鎖;建議批次提交 (如每 500 條)。
繞過 Recordset 更新機制,直接執行參數化 INSERT,效能更高、錯誤更明確。
CString sql = _T("INSERT INTO MyTable (Col1, Col2, Col3) VALUES (?, ?, ?)");
_CommandPtr pCmd; pCmd.CreateInstance(__uuidof(Command));
pCmd->ActiveConnection = m_pConnection;
pCmd->CommandText = _bstr_t(sql);
pCmd->Prepared = TRUE;
for (int i = 0; i < nCount; ++i) {
pCmd->Parameters->Refresh(); // 首次取得參數資訊
pCmd->Parameters->GetItem(0)->Value = _variant_t(val1[i]);
pCmd->Parameters->GetItem(1)->Value = _variant_t(val2[i]);
pCmd->Parameters->GetItem(2)->Value = _variant_t(val3[i]);
pCmd->Execute(NULL, NULL, adExecuteNoRecords);
}
PutCollect 未傳入 VT_EMPTY 或 VT_NULL (除非資料庫允許 NULL)。_variant_t 自動轉型,但日期、數值精度、字串長度超限會導致更新失敗。adOpenKeyset, adOpenDynamic, adOpenStatic + adLockOptimistic/adLockBatchOptimistic)。ADO Error 0x800A0CB3 (Object or provider is not capable of performing requested operation) → 游標/鎖類型不支援。Recordset->State 是否 adStateOpen。Recordset->UpdateBatch(adAffectAll) 替代單條 Update。_ConnectionPtr->Properties["Trace"] = true) 觀察底層 SQL。