質問

テキストの壁には申し訳ありませんが、これには説明が必要です。投稿するにはコードが多すぎます...

固定幅のファイルをインポートして、データ入力が必要なメソッドのアクセスに使用しています。 transferTextを使用してファイルを2つの仕様にインポートします(1つはグローバル、もう1つは特別な状況です)。

DAOを使用してTableDefsのすべてのFieldオブジェクトを循環する機能があり、AutoIncrement PKを含む複製テーブルを構築するため、これらのレコードを編集できます。 INSERT INTOを使用して、そのテーブルにデータをプッシュします。

すばらしい。エラーが見つかった場合、ユーザーはデータ入力に入り、手動で修正します。これは、400文字の行をふるいにかけ、想定どおりにすべてを再編成します。すばらしい!

問題:データ入力の変更が行われると、コミットボタンが押され、フォーム外のモジュール内の関数が呼び出されます。データ入力フォームを閉じて、元のテーブルから自動インクリメントされたPKを差し引いた情報をプッシュし、複製されたテーブルをIDでドロップし、エラーをもう一度検索する新しいテーブルを生成します...

元の状態に戻りますが、IDテーブルは削除されません。このテーブルがロックされていることを示すメッセージを常に私に返します。すべての関数/サブが終了するまで、テーブルが永久にロックダウンされていることに気付きました。コードをステップ実行するたびに、手動で削除することはできません。実行が終了したら、削除することができます。

フォーム内のコマンドを使用してこれを呼び出したため、すべてのコードが終了し、フォームが終了するまでロックが解除されず、その処理が実行されると想定しています。何かご意見は?はい、これは非常に野barですが、非常にうまく機能します。この他のテーブルを惑星からリッピングして、更新されたコピーをドロップできるようにする必要があります...

最悪の場合、ユーザーがフォームを閉じてメインフォームの別のボタンを押すようにすることもできますが、これはユーザーの柔軟性を念頭に置いて設計されています。しかし、これは今では十分な注意を払っており、たとえ最適な解決策でなくても、少なくとも解決策を見つけたいと考えています。

-EDIT-

この問題では2つのフォームが使用されます

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-データ入力フォーム

このフォームを開くとすぐに、テーブルtempExtractIDがロックされ、テーブルを削除できなくなります。フォームへのレコードソースは、problems_tのIDに対してtempExtractIDを照会し、キー入力する必要があるものだけを返します。

フォームが完全に終了するまで、テーブルを削除できません。データ入力フォームのボタンを押して変更をコミットします。ロックエラーが発生する前に起動するコードは 5 行のみです。

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

これは、フォームが開かれる(テーブルが最初にロックされる)間に実行される唯一のコードであり、すべてのサブ&機能が完了しました。

役に立ちましたか?

解決

フォームのレコードソースをvbNullStringに設定し、テーブルを削除することをお勧めします。このテーブルにコンボボックスなどがバインドされていない限り、これは機能するはずです。

他のヒント

コードがないと言うのは難しいですが、DAOを使用している場合は、コードオブジェクトをクリーンアップする必要があります。つまり、データベースオブジェクトをNothingに設定し、レコードセットオブジェクトを閉じてNothingに設定することを意味します。

  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

VBAはこれらのオブジェクトがスコープ外に出るときにそれらをクリーンアップすることになっていますが、100%の信頼性はありません(VBAは参照カウントを使用してオブジェクトを解放できるかどうかを追跡するため、参照はクリアされました)。

開いたままになっているオブジェクトがロックの原因である可能性が最も高いため、オブジェクト変数を終了した後は、必ずオブジェクト変数をクリーンアップする必要があります。

DoCmd.RunSQLを使用していることを確認してから編集します。

DoCmd.RunSQLの使用が問題の原因である可能性があります。それは確かにあなたの接続のプログラマティックな管理を奪うものです。代わりにDAOを使用する場合、接続を制御でき、エラーを処理しないというDoCmd.RunSQLの本当の落とし穴を回避できます。 DMLまたはDDLステートメントが完全に正常に完了できない場合、全体が失敗します。たとえば、100件のレコードを追加し、そのうち10件がキー違反で失敗した場合、DoCmd.RunSQLは透過的に90件を追加し、10件の失敗を報告しません。更新やその他のDML / DDLステートメントでも同じです。 DoCmd.RunSQL" helpfully"可能な限り多くの更新をサイレントに完了し、一部の更新が失敗したことを知らないままにします。

許可されます。たとえば、PKコリジョンの可能性があることがわかっているレコードを追加し、CPUサイクルを外部結合に費やしたくない場合に、それを発生させたい場合があります。追加するレコードのセット。

しかし、ほとんどの場合、そうではありません。

上記のコメントで述べたように、DoCmd.RunSQLを透過的に置き換えるように設計された関数を使用し、DAO Executeステートメントとエラー処理を使用します。私はそれをSOに数回投稿しました(こちら)、そして現在最もアクティブな開発プロジェクトで本番環境で使用しているバージョンは次のとおりです。

  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

(トランザクションはトラブルシューティングの時間がない問題を引き起こしているためコメントアウトされています)

これらの行を置き換えることができます:

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

...これ:

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

これを行うこともできます:

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

関数は各Executeに対して.RecordsAffectedを返すため、イミディエイトウィンドウに出力するか、戻り値を変数に割り当てるか、既存の変数を変数に渡し、その変数を操作します。

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

要点は、Executeステートメントにエラーがある場合、全体が失敗することです(そして、エラーメッセージがポップアップ表示されます-エラーがある場合、-1などを代わりに返すように変更することもできます) MsgBoxをポップする)。

この関数は、事前にキャッシュされたデータベース変数を渡すことで最も頻繁に使用するため、後でクリーンアップしたくありません。 CurrentDB()以外の別のデータベースを使用している場合、外部データベースを指すデータベース変数が閉じられ、Nothingに設定されていることを確認する必要があります。それがなければ、トップレベルのデータベースオブジェクトのロックが維持され、LDBファイルは開いたままアクティブになります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top