Frage

Sorry für die Wand von Text Jungs aber dieses erfordert expliaining, viel zu viel Code zu schreiben ...

Ich bin Import feste Breite Dateien zugreifen in Methoden, die Dateneingabe erfordern. Ich importiere die Datei mit Transfertext in zwei Spezifikationen (diejenigen, global, der andere besondere Umstände).

Ich habe eine Funktion, die DAO, um durch alle Feldobjekte in TableDefs verwendet eine doppelte Tabelle mit einem AutoIncrement PK zu bauen, so habe ich die Möglichkeit, diese Datensätze zu bearbeiten. Ich schiebe die Daten in dieser Tabelle mit INSERT INTO.

Arbeiten groß. Fehler werden gefunden, Benutzer geht in die Dateneingabe manuell zu korrigieren, die durch 400 Zeichen Linien schlägt Sichtung und seine alles so sein soll reorganisiert. Funktioniert prima!

Das Problem : Wenn die Dateneingabe Änderungen ein Commit gemacht werden Taste gedrückt wird, die eine Funktion in einem Modul ruft außerhalb des Formulars. Sie schließt das Dateneingabeformular und schiebt die Informationen wieder auf die ursprüngliche Tabelle minus dem autoinkrementierten PK, und sollte die replizierte Tabelle mit IDs löschen und einen neuen erzeugt noch einmal für Fehlersuche ...

Sie drückt wieder auf den ursprünglichen ganz gut, aber es wird die ID-Tabelle nicht fallen. Immer wieder zu mir mit einer Nachricht, die diese Tabelle, die gesperrt ist. Ive bemerkte die Tabelle indefiniatly, bis alle Funktionen / subs Ausgang gesperrt. Zu jeder Zeit durch den Code Schreitet ich es manuell nicht löschen kann, sobald die Ausführung Ich bin in der Lage, es zu entfernen beendet ist.

Ich gehe davon aus, dass, da ich dies durch einen Befehl in Form genannt, dass die Sperre nicht, bis alle Oberflächen Code freigegeben werden und die Form kann seine Sache nennen beenden und tun. Irgendwelche Gedanken? Ja, das ist sehr barbarisch, aber es funktioniert ganz gut, ich aus dem Planeten gerade diese andere Tabelle zerreißen müssen in der Lage sein, damit ich eine aktualisierte Kopie ReDrop kann ...

Im schlimmsten Fall kann ich den Benutzer macht das Formular schließen und eine andere Taste in der Hauptform getroffen, aber das entworfen wird stark mit Benutzern compitence im Auge behalten. Doch dies jetzt meine volle Aufmerksamkeit hat und möchte zumindest um eine Lösung zu finden, auch wenn es nicht als optimal ist.

-EDIT -

Zwei Formen werden in diesem Problem verwendet

FormA (Role: Load in and search for problems)

Examine button is pressed that:

 - Uses TextTransfer based on predefined specs into tempExtract to
       import the file

 - DAO fires off on the Fields collection in tableDefs for
   tempExtract, creates new table tempExtractID

 - Performs searches through the file to find errors.  Errors are saved to
   a table Problem_t.  Table contains Problem_ID (Set from the ID field
   added to tempExtractID) and Description

 - Execution of these tasks is successfully requerying the initial
   form to showing a list of problems and number of occurances.  A button
   gains visibility, with onClick that opens the form DataEntry.            

 - At this point in the code after DAO execution, I can DROP the table
   tempExtractID.  DAO is NOT used again and was only used to build a new table.

FormB - Dateneingabeformular

Sobald ich dieses Formular öffnen, wird die Tabelle tempExtractID gesperrt und ich kann die Tabelle nicht fallen. Die Datenherkunft des Formulars querys tempExtractID gegen die IDs in Problems_t nur zurück, was wir eingeben müssen.

Ich kann die Tabelle nicht fallen, bis das Formular vollständig beendet wird. Schaltfläche auf dem Formular Dateneingabe gedrückt Änderungen zu übernehmen, in denen es nur 5 Codezeilen, die aus Feuer, bevor ich meine Sperre Fehler.

*Xargs refers to the list of Field names pulled earlier through DAO.  As DAO loops through Field objects, the physical names are added to an Xargs String which is placed in this table.  Basically everything but the AutoNumber is being inserted back

    docmd.Close acForm, "frmDataEntry", acSaveNo
    call reInitializeExtract
         > docmd.RunSQL "DELETE FROM tempExtract"
         > docmd.RunSQL "INSERT INTO tempExtract SELECT (" & DLookup("Value", "CONFIG_t", "Item = 'Xargs'" & ") FROM tempExtractID"
    docmd.DeleteObject acTable, "tempExtractID"

Dies ist der einzige Code, der zwischen dem Zeitpunkt ausgeführt wird, in dem das Formular geöffnet wird (wo der Tisch zuerst gesperrt wird) und weiterhin gesperrt werden, bis alle U-Boote und Funktionen abgeschlossen haben.

War es hilfreich?

Lösung

Ich schlage vor, die Einstellung der Datenherkunft des Formulars vbNullString und dann die Tabelle zu löschen. Dies sollte funktionieren, es sei denn, Sie auch Comboboxen haben und so weiter auf diese Tabelle gebunden ist.

Andere Tipps

Ohne Code ist es schwer zu sagen, aber wenn Sie DAO verwenden, müssen Sie Ihren Code Objekte bereinigen. Das bedeutet, Einstellung auf Nothing Ihrer Datenbankobjekte, und Schließen und Einstellen auf Nothing keine Cord-Objekte.

  Dim db As DAO.Database
  Dim rs As DAO.Recordset

  Set db = DBEngine.OpenDatabase("[path to database]")
  Set rs = db.OpenRecordset("[SELECT statement]")
  rs.Close
  Set rs = Nothing
  db.Execute("[DML or DDL statement]", dbFailOnError)
  db.Close
  Set db = Nothing

  Set db =CurrentDB
  Set rs = db.OpenRecordset("[SELECT statement]")
  rs.Close
  Set rs = Nothing
  Set db = Nothing  ' you don't close a db variable initialized with CurrentDB

Während VBA soll diese Objekte bereinigen, wenn sie außerhalb des Bereichs geht, ist es nicht 100% zuverlässig (weil VBA Referenzzählung verwendet, um zu verfolgen, ob ein Objekt freigegeben werden kann, und es weiß nicht immer, wenn alle die Referenzen gelöscht wurden).

Objekte offen gelassen ist die wahrscheinlichste Quelle der Schleusen, so sollten Sie sicherstellen, dass Sie Ihre Objektvariablen sind Reinigung, nachdem Sie mit ihnen fertig sind.

EDIT nach zu sehen, dass Sie verwenden DoCmd.RunSQL:

Mit DoCmd.RunSQL ist wahrscheinlich die Ursache des Problems. Es ist sicherlich etwas, das Ihre programmatische Verwaltung Ihrer Verbindungen wegnimmt. Wenn Sie DAO stattdessen verwenden, werden Sie die Kontrolle über die Verbindung haben, sowie die reale Gefahr von DoCmd.RunSQL zu vermeiden, die ist, dass es sich nicht um Fehler zu behandeln. Wenn eine DML oder DDL-Anweisung nicht erfolgreich vollständig ausfüllen kann, sollte das Ganze nicht. Zum Beispiel, wenn Sie 100 Datensätze und 10 von ihnen sind Anfügen für Schlüsselverletzungen scheitern, DoCmd.RunSQL wird transparent über die 90 hängen und somit nicht die entsprechenden 10 FAILURES. Es ist das gleiche mit Updates und einer anderen DML / DDL-Anweisung. DoCmd.RunSQL „helfend“ leise vervollständigt, da viele der Updates kann es, so dass Sie keine Ahnung, dass ein Teil davon wurde nicht abgeschlossen.

Zugegeben, in manchen Fällen möchten Sie vielleicht, dass das geschehen, zum Beispiel, wenn Sie Datensätze sind anhängt, die Sie vielleicht wissen, PK Kollisionen haben und wollen nicht die CPU-Zyklen auf einem äußeren verbringen kommen, dass die Duplikate aus der beseitigt Satz von Datensätzen sind Anfügen Sie.

Aber die meiste Zeit, das ist nicht der Fall ist.

Wie ich oben in meinem Kommentar gesagt, verwende ich eine Funktion, die transparent gestaltet ist DoCmd.RunSQL zu ersetzen und verwendet ein DAO Execute-Anweisung und Fehlerbehandlung. Ich habe es ein paar Mal geschrieben auf SO ( hier ist ein ), und hier ist die Version, die ich in meiner Zeit am meisten aktiven Entwicklungsprojekt in den produktiven Einsatz haben:

  Public Function SQLRun(strSQL As String, Optional db As Database, _
       Optional lngRecordsAffected As Long) As Long
  On Error GoTo errHandler
    Dim bolCleanup As Boolean

    If db Is Nothing Then
       Set db = CurrentDb
       bolCleanup = True
    End If
    'DBEngine.Workspaces(0).BeginTrans
    db.Execute strSQL, dbFailOnError
    lngRecordsAffected = db.RecordsAffected
    'DBEngine.Workspaces(0).CommitTrans

  exitRoutine:
    If bolCleanup Then
       Set db = Nothing
    End If
    SQLRun = lngRecordsAffected
    'Debug.Print strSQL
    Exit Function

  errHandler:
    MsgBox "There was an error executing your SQL string: " _
       & vbCrLf & vbCrLf & Err.Number & ": " & Err.Description, _
       vbExclamation, "Error in SQLRun()"
    Debug.Print "SQL Error: " & strSQL
    'DBEngine.Workspaces(0).Rollback
    Resume exitRoutine
  End Function

(die Transaktionen kommentiert, weil sie Probleme verursacht wurden, dass ich keine Zeit hatte, zu beheben)

Sie können diese Zeilen von Ihnen ersetzen:

  DoCmd.RunSQL "DELETE FROM tempExtract"
  DoCmd.RunSQL "INSERT INTO tempExtract SELECT (" _
    & DLookup("Value", "CONFIG_t", "Item = 'Xargs'" & ") FROM tempExtractID"

... mit dieser:

  SQLRun "DELETE FROM tempExtract"
  SQLRun "INSERT INTO tempExtract SELECT (" _
    & DLookup("Value", "CONFIG_t", "Item = 'Xargs'" & ") FROM tempExtractID"

Sie können auch dies tun:

  Debug.Print SQLRun("DELETE FROM tempExtract") & " records deleted."
  Debug.Print SQLRun("INSERT INTO tempExtract SELECT (" _
    & DLookup("Value", "CONFIG_t", "Item = 'Xargs'" _
    & ") FROM tempExtractID") & " records inserted."

Da die Funktion gibt den .RecordsAffected für jedes Führen Sie in dem Direkt-Fenster drucken können, oder Sie können den Rückgabewert einer Variablen zuweisen, oder übergeben Sie eine vorhandene Variable durch, um es und die Arbeit mit dieser Variablen so:

  Dim lngRecordsAffected As Long
  ...
  Call SQLRun("DELETE FROM tempExtract", , lngRecordsAffected)
  Debug.Print lngRecordsAffected & " records deleted."
  Call SQLRun("INSERT INTO tempExtract SELECT (" _
    & DLookup("Value", "CONFIG_t", "Item = 'Xargs'" _
    & ") FROM tempExtractID", , lngRecordsAffected)
  Debug.Print lngRecordsAffected & " records inserted."

Der Punkt ist, dass, wenn Fehler auf die Anweisung auszuführen sind, wird die ganze Sache nicht (und eine Fehlermeldung Pop-up - Sie könnten es ändern wollen, so dass, wenn es einen Fehler gibt sie -1 zurück oder so statt von popping eine MsgBox).

Ich benutze diese Funktion am häufigsten von in einer vorher zwischengespeicherten Datenbankvariable vorbei, so will ich es nicht danach aufzuräumen. Wenn Sie eine andere Datenbank anders als CurrentDB sind () verwenden, die Sie wirklich wollen, dass jede Datenbankvariable zeigt auf externe db machen, ist geschlossen und auf Nichts. Ohne diese werden Sperren auf die Top-Level-Datenbankobjekte gehalten, und die LDB-Datei bleibt offen und aktiv.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top