Pergunta

Desculpem a parede de caras texto mas este requer expliaining, maneira muito código para postar ...

Estou a importação de arquivos de largura fixa para o acesso em métodos que exigem entrada de dados. Eu importar o arquivo usando TransferText em duas especificações (aqueles global, o outro é circunstância especial).

Eu tenho uma função que usa o DAO para percorrer todo o campo objetos em TableDefs para construir uma tabela duplicado incluindo um AutoIncrement PK, por isso tenho a capacidade de editar esses registros. Eu empurrar os dados para essa tabela com INSERT INTO.

Funciona muito bem. Os erros são encontrados, o usuário vai para a entrada de dados para corrigi-los manualmente que bate peneirar 400 linhas de caráter e reorganizar tudo da maneira seu suposto ser. Funciona muito bem!

O problema : Quando as alterações de entrada de dados são feitas a cometer botão é pressionado que chama uma função dentro de um fora módulo do formulário. Ele fecha o formulário de entrada de dados e empurra a volta informações para a tabela original menos o PK autoincremented, e é suposto para soltar a tabela replicada com ID de e gerar uma nova busca, mais uma vez por erros ...

Ele empurra de volta para o bem original, mas não vai cair tabela de ID. Sempre retorna a mim com uma mensagem indicando esta tabela está bloqueado. Ive notado a tabela é indefiniatly bloqueado até que todas as funções / saída subs. Em qualquer stepping vez através do código que não pode excluí-lo manualmente, uma vez que a execução tenha terminado eu sou capaz de removê-lo.

Estou assumindo que uma vez eu chamei isso por meio de um comando na forma, que o bloqueio não será liberado até que todos os acabamentos de código ea forma terminar pode ser chamado e fazer a sua coisa. Alguma ideia? Sim isso é muito bárbara, mas ele funciona muito bem, eu só preciso ser capaz de rasgar essa outra mesa fora do planeta para que eu possa redrop uma cópia atualizada ...

No pior caso, posso fazer o usuário fechar o formulário de fora e bater outro botão no formulário principal, mas isso está sendo projetado fortemente com compitence usuário em mente. No entanto, este tem agora toda a minha atenção e gostaria de, pelo menos, encontrar uma solução, mesmo que não é o ideal um.

-EDIT -

Duas formas são usados ??neste problema

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 - Formulário de Entrada de Dados

Assim que eu abrir esse formulário, o tempExtractID mesa fica bloqueado e não pode cair da mesa. O OrigemDoRegistro para a forma querys tempExtractID contra o ID está em Problems_t para retornar apenas o que precisamos chave.

Eu não posso descartar a tabela até que o formulário foi totalmente encerrado. Botão no formulário de entrada de dados é pressionado para confirmar as alterações, em que não são apenas os 5 linhas de código que começa a disparar antes de eu chegar o meu erro de bloqueio.

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

Este é o único código que é executado entre o momento em que o formulário é aberto (onde a tabela primeira fica bloqueado) e continua a ser bloqueada até que todos os subs & funções tenham concluído.

Foi útil?

Solução

Eu sugiro definir o OrigemDoRegistro do formulário para vbNullString e excluindo a mesa. Isso deve funcionar, a menos que você também tem comboboxes e assim por diante obrigado a esta tabela.

Outras dicas

Sem código é difícil dizer, mas se você estiver usando DAO, você precisa limpar seus objetos de código. Isso significa definir como Nothing seus objetos de banco de dados, e fechar e definir como Nothing quaisquer objetos de registros.

  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

Enquanto VBA é suposto para limpar estes objetos quando eles saem de escopo, não é 100% confiável (porque VBA utiliza a contagem de referência para acompanhar se um objeto pode ser lançado, e isso nem sempre sabe quando todos as referências foram apagadas).

Objetos deixados em aberto é a fonte mais provável dos bloqueios, então você deve certificar-se de que você está limpando suas variáveis ??de objeto depois que terminar com eles.

EDIT depois de ver que você está usando DoCmd.RunSQL:

Usando DoCmd.RunSQL é provável que a causa do problema. É certamente algo que tira a sua gestão programática de suas conexões. Se você usar DAO em vez disso, você terá controle sobre a conexão, bem como evitar a armadilha real da DoCmd.RunSQL, o que é que ele não lida com erros. Se uma instrução DML ou DDL não pode concluir com êxito na íntegra, a coisa toda deve falhar. Por exemplo, se você está anexando 100 registros e 10 deles falhar por violações de chave, DoCmd.RunSQL, transparentemente, anexar os 90 e não informarem o 10 falhas. É o mesmo com atualizações e qualquer outra declaração DML / DDL. DoCmd.RunSQL "amavelmente" completa em silêncio, enquanto muitas das atualizações como ele pode, deixando-o sem ter idéia do que alguns dos que não conseguiu completar.

Com certeza, em alguns casos, você pode querer que isso aconteça, por exemplo, se você está anexando registros que você sabe pode ter colisões PK e não quer gastar os ciclos de CPU em uma associação externa que elimina as duplicatas da conjunto de registros que você está anexando.

Mas a maior parte do tempo, que não é o caso.

Como eu disse no meu comentário acima, eu uso uma função que é projetado para substituir transparente DoCmd.RunSQL e utiliza um DAO Executar declaração e tratamento de erros. Tenho postado um par de vezes no SO ( aqui está um ), e aqui está a versão que tenho em uso em produção em meu projeto de desenvolvimento atualmente mais ativo:

  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

(as transações são comentados porque eles estavam causando problemas que não têm tempo para solucionar problemas)

Você pode substituir essas linhas de sua:

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

... com isto:

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

Você também pode fazer isso:

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

Uma vez que a função retorna o .RecordsAffected para cada executar, você pode imprimir para a janela imediata, ou você pode atribuir o valor de retorno a uma variável, ou passar uma variável existente através a ele e trabalhar com essa variável assim:

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

O ponto é que se houver erros na instrução de execução, a coisa toda vai falhar (e aparecer uma mensagem de erro - você pode querer mudá-lo de modo que se houver um erro ele retorna -1 ou alguma vez de popping um MsgBox).

Eu uso essa função na maioria das vezes, passando em uma variável de banco de dados pré-armazenados em cache, então eu não quero limpá-lo depois. Se você estiver usando um banco de dados diferente que não seja CurrentDB (), você realmente quer ter certeza de qualquer variável de banco de dados apontando para o seu db externa está fechada e definida como Nothing. Sem isso, os bloqueios são mantidos nos objetos de banco de dados de nível superior e o arquivo LDB permanece aberta e ativa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top