ADODB:Recordset: Problem mit Update



  • Hallo,

    habe folgendes Problem:

    m_RecPtr->PutCursorLocation(ADODB::adUseClient);
    
    m_RecPtr->PutCursorType(ADODB::adOpenForwardOnly);
    m_RecPtr->PutLockType (ADODB::adLockOptimistic);
    
    m_CommPtr->PutCommandText(str);
    m_CommPtr->PutCommandTimeout ( 20 );
    m_CommPtr->PutRefActiveConnection (m_pDatabase->m_ConnPtr.GetInterfacePtr());
    m_CommPtr->PutCommandType(ADODB::adCmdText);
    m_RecPtr = m_CommPtr->Execute(NULL,NULL,ADODB::adCmdText);
    

    Alle Select-Anweisung laufen auch durch. Zu einem späteren Zeitpunkt wird mit dem Recordset weiter gearbeitet:

    m_RecPtr->PutCollect(Fields,Values);
    

    Diese Anweisung bricht mit einer Exception ab:

    Das aktuelle Recordset unterstützt keine Aktualisierung. Hierbei handelt es sich möglicherweise um eine Einschränkung seitens des Providers oder des gewählten LockTypes.
    

    Scheinbar wird der Recordset-Locktyp (Zeile 3) überschrieben. Hat der CommandPointer auch einen LockTyp? Habt ihr einen Tipp für mich?

    Danke!

    Gruß

    TW



  • Ich schätze mal das der Cursor irgendeinen Vorgang der da stattfindet nicht unterstützt. ADODB::adOpenForwardOnly ist die simpelste Variante. Nimm doch lieber adOpenKeyset oder (falls unterstützt) adOpenDynamic. Damit hast du dann sogar bidirektionales Scrolling und kannst Änderungen im Recordset sichtbar machen.
    (edit)
    Falls das auch nicht hilft solltest du versuchen den Cursortyp nochmal nach Aufruf der Execute-Funktion des Command Objekts zu setzen. (Vermutlich überschreibt die Funktion einfach alles)



  • Vielen Dank für die Tipps!

    Nimm doch lieber adOpenKeyset oder (falls unterstützt) adOpenDynamic.
    Habe die verschiedenen CursorTypen probiert. Leider kein Erfolg. Kann es evtl. noch am Provider liegen? Nutze "SQLOLEDB" als Provider.

    Falls das auch nicht hilft solltest du versuchen den Cursortyp nochmal nach Aufruf der Execute-Funktion des Command Objekts zu setzen. (Vermutlich überschreibt die Funktion einfach alles)
    Das hatte ich auch schon versucht. Fehlermeldung:
    Das ist auf ein geöffnetem Recordset nicht möglich.



  • Hmm und wenn du anstatt des "Umweges" über das Command Objekt gleich die Open Funktion des Recordset Objekts nimmst? Da kannste nämlich gleich alle mit übergeben und kriegstn fertiges Recordset zurück.
    So ungefähr:

    m_pRecordSet->PutCursorType(ADODB::adOpenKeyset);
    // strSQL - String mit Select Statement
    // vtDBConnection - IDispatch DB Connection
    m_pRecordSet->Open(strSQL, vtDBConnection, ADODB::adOpenKeyset, ADODB::adLockOptimistic, ADODB::adCmdText);
    


  • Das ist richtig. Hatte ich vorher auch. Das klappte auch.

    Allerdings möchte ich den Timeout für jeden Recordset setzten und das soll laut Microsoft nur über das CommandObject gehen.

    Hast Du schon eine Anwendung mit Timeout versehen, so dass Du steuern kannst das ein Update z.B. ein Timeout von 3 sek. hat und ein Select z.B. 120 sec?



  • Ich habe gemerkt das durch das Execute der eine neue Instanz des Recordset(m_RecPtr) wird. Deswegen sind auch Änderungen vor dem Execute unwirksam:

    m_RecPtr = m_CommPtr->Execute(NULL,NULL,ADODB::adCmdText);
    


  • TW_2 schrieb:

    ...
    Hast Du schon eine Anwendung mit Timeout versehen, so dass Du steuern kannst das ein Update z.B. ein Timeout von 3 sek. hat und ein Select z.B. 120 sec?

    Nein, ich weiss auch nicht so genau ob das überhaupt sinn macht. Wenn du damit Deadlocks verhindern willst gibts da bessere Möglichkeiten.



  • ADODB::CursorLocationEnum CursorLocation = m_RecPtr->GetCursorLocation();
    ADODB::LockTypeEnum LockTypeEnum = m_RecPtr->GetLockType();
    ADODB::CursorTypeEnum CursorTypeEnum = m_RecPtr->GetCursorType();
    

    Wenn ich das vor

    m_RecPtr->PutCollect(Fields,Values);
    

    aufrufe, bekomme ich ClientCursor, AdReadOnly und adOpenstatic. Jetzt ist klar das das Update nicht funktioniert. Habe aber leider keine Ahnung wie ich den Locktype ändern kann.

    Wenn du damit Deadlocks verhindern willst gibts da bessere Möglichkeiten.
    Ja, haben mit unserer Unicode-Version und ADO-DB Blockaden-Probleme. Mit der ANSI und ODBC nicht so. Welche Möglichkeiten meinst Du?



  • Das einfachste ist wohl, das NOWAIT Flag zu setzen. Geht bei den meissten Treibern im Connection String mit "NOWAIT=1". Der springt dann sofort raus (und wirft ne Exception), wenn eine andere Transaktion einen betroffenen Satz blockiert.



  • Hört sich gut an. Wäre eine alternative. Kannst Du mir bitte ein Beispiel geben, wie das im Code aussehen würde? Danke!



  • Das kommt einfach in den Connection String den du beim Öffnen der Verbindung an das Connection-Objekt übergibst.
    Also z.B.

    "Provider=MSDASQL.1;Data Source=TEST;NOWAIT=1"
    

    Natürlich musste MSDASQL (Microsoft ADO via ODBC) noch durch deinen Provider ersetzen und den Data Source Namen ändern. Kommt allerdings auf den Treiber an, ob das NOWAIT funktioniert. Hab es hier mit drei verschiedenen Treibern (Oracle und Firebird) probiert und es ging bei allen.



  • Werde mein Glück mit "SET LOCK_TIMEOUT" versuchen. Vielen Dank für deine Hilfe!


Anmelden zum Antworten