Domanda

Ci scusiamo per il muro di testo ragazzi, ma questo richiede l'espansione, troppo codice per pubblicare ...

Sto importando file a larghezza fissa in accesso con metodi che richiedono l'inserimento di dati. Importo il file usando transferText in due specifiche (una globale, l'altra è una circostanza speciale).

Ho una funzione che utilizza DAO per scorrere tutti gli oggetti Field in TableDefs per creare una tabella duplicata che include un PK AutoIncrement, quindi ho la possibilità di modificare questi record. Inserisco i dati in quella tabella con INSERT INTO.

Funziona alla grande. Vengono rilevati errori, l'utente accede all'immissione dei dati per correggerli manualmente, battendo la selezione di 400 righe di caratteri e riorganizzando tutto come dovrebbe essere. Funziona alla grande!

Il problema : quando vengono apportate modifiche all'immissione dei dati, viene premuto un pulsante di commit che chiama una funzione all'interno di un modulo al di fuori del modulo. Chiude il modulo di immissione dei dati e riporta le informazioni alla tabella originale meno il PK autoincrementato, ed è SUPPOSTO per DROP la tabella replicata con ID e ne genera una nuova alla ricerca di errori ...

Torna indietro all'originale, ma non DROP la tabella ID. Ritorna sempre da me con un messaggio che indica che questa tabella è bloccata. Ho notato che la tabella è bloccata indefinitamente fino all'uscita di tutte le funzioni / sottotitoli. In qualsiasi momento, sfogliando il codice non posso eliminarlo manualmente, una volta terminata l'esecuzione sono in grado di rimuoverlo.

Suppongo che da quando ho chiamato questo tramite un comando nel modulo, che il blocco non verrà rilasciato fino a quando tutto il codice non termina e il modulo termina può essere chiamato e fare la sua cosa. qualche idea? Sì, questo è molto barbaro ma funziona abbastanza bene, devo solo essere in grado di strappare quest'altro tavolo dal pianeta in modo da poter ridisegnare una copia aggiornata ...

Nel peggiore dei casi posso far chiudere il modulo all'utente e premere un altro pulsante nel modulo principale, ma questo è stato progettato pesantemente tenendo presente la competenza dell'utente. Tuttavia, questo ora ha tutta la mia attenzione e vorrei almeno trovare una soluzione anche se non è ottimale.

-Edit -

In questo problema vengono utilizzati due moduli

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.

Modulo B - Modulo di inserimento dati

Non appena apro questo modulo, la tabella tempExtractID viene bloccata e non riesco a eliminare la tabella. L'origine record del modulo richiede tempExtractID rispetto all'ID in Problems_t per restituire solo ciò che è necessario digitare.

Non riesco a eliminare la tabella fino a quando il modulo non è stato completamente chiuso. Viene premuto il pulsante sul modulo di inserimento dati per confermare le modifiche, in cui sono presenti solo 5 righe di codice che vengono attivate prima che venga visualizzato l'errore di blocco.

*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"

Questo è l'unico codice che viene eseguito tra il momento in cui viene aperto il modulo (dove viene bloccata la tabella per la prima volta) e continua a essere bloccato fino a quando tutti i sottotitoli & amp; funzioni completate.

È stato utile?

Soluzione

Suggerisco di impostare l'origine record del modulo su vbNullString e quindi di eliminare la tabella. Questo dovrebbe funzionare, a meno che tu non abbia anche caselle combinate e così via associato a questa tabella.

Altri suggerimenti

Senza codice è difficile da dire, ma se si utilizza DAO, è necessario ripulire gli oggetti del codice. Ciò significa impostare su Nothing oggetti del database e chiudere e impostare su Nothing qualsiasi oggetto recordset.

  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

Mentre VBA dovrebbe ripulire questi oggetti quando escono dall'ambito, non è affidabile al 100% (perché VBA utilizza il conteggio dei riferimenti per tenere traccia del fatto che un oggetto può essere rilasciato e non sempre sa quando tutti i riferimenti sono stati cancellati).

Gli oggetti lasciati aperti sono la fonte più probabile dei blocchi, quindi dovresti assicurarti di ripulire le variabili degli oggetti dopo aver finito con essi.

MODIFICA dopo aver visto che stai usando DoCmd.RunSQL:

L'uso di DoCmd.RunSQL è probabilmente la causa del problema. È certamente qualcosa che toglie la gestione programmatica delle tue connessioni. Se invece usi DAO, avrai il controllo della connessione, oltre a evitare il vero trabocchetto di DoCmd.RunSQL, che non gestisce gli errori. Se un'istruzione DML o DDL non può essere completata correttamente, l'intera operazione dovrebbe fallire. Ad esempio, se si stanno aggiungendo 100 record e 10 di questi falliscono per violazioni chiave, DoCmd.RunSQL aggiungerà in modo trasparente i 90 e NON SEGNALA I 10 GUASTI. È lo stesso con gli aggiornamenti e qualsiasi altra istruzione DML / DDL. DoCmd.RunSQL "utile" " completa silenziosamente quanti più aggiornamenti possibile, lasciandoti senza la minima idea che alcuni di essi non sono stati completati.

Concesso, in alcuni casi potresti volere che ciò accada, ad esempio, se stai aggiungendo record che conosci potrebbero avere collisioni PK e non vuoi spendere i cicli della CPU su un join esterno che elimina i duplicati dal set di record che stai aggiungendo.

Ma il più delle volte, non è così.

Come ho detto nel mio commento sopra, utilizzo una funzione progettata per sostituire in modo trasparente DoCmd.RunSQL e utilizza un'istruzione DAO Execute e la gestione degli errori. L'ho pubblicato un paio di volte su SO ( eccone uno ), ed ecco la versione che ho in produzione nel mio progetto di sviluppo attualmente più attivo:

  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

(le transazioni sono commentate perché causavano problemi che non avevo tempo di risolvere)

Puoi sostituire queste tue righe:

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

... con questo:

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

Puoi anche farlo:

  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."

Poiché la funzione restituisce .RecordsAffected per ogni esecuzione, è possibile stampare nella finestra immediata oppure è possibile assegnare il valore restituito a una variabile o passare una variabile esistente attraverso di essa e lavorare con quella variabile in questo modo:

  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."

Il punto è che se ci sono errori nell'istruzione Execute, l'intera cosa fallirà (e farà apparire un messaggio di errore - potresti volerlo cambiare in modo che se c'è un errore restituisca -1 o alcuni invece di scoppiare un MsgBox).

Uso questa funzione il più delle volte passando una variabile di database pre-cache, quindi non voglio ripulirla in seguito. Se stai utilizzando un database diverso da CurrentDB (), devi davvero assicurarti che qualsiasi variabile di database che punta al tuo db esterno sia chiusa e impostata su Nothing. Senza di ciò, i blocchi vengono mantenuti sugli oggetti del database di livello superiore e il file LDB rimane aperto e attivo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top