2

ログ メッセージの膨大なセットを含む SQLite データベースがあります。

これをリスト ビューで表示したい (wxWidgets を使用)。

ユーザーは、(列ヘッダーを押して) リストを並べ替えたり、結果セットにフィルターを適用したり、スクロール バーを使用して通常のリストと同様にナビゲートしたりできます。ユーザーは、リスト内の 1 つまたは複数のエントリを選択して削除することもできます。

仮想リスト モデルがあります。リスト ビューはモデルに特定の行の内容を要求します。モデルは、現在のフィルター条件と順序を使用して選択クエリを発行し、結果から対応する行を返します。

高速化するために、結果のページ キャッシュを保持します。行が要求されると、LIMIT と OFFSET を使用してページ全体 (〜 100 行) をフェッチし、ページから特定の行を返します。いくつかのページを保存し、次に行が要求されたときに、キャッシュされたページの 1 つで利用できるかどうかを最初に調べます。この手法は、多数のエントリ (50k 以上)がある場合でも高速で応答性が高いことが証明されています。

問題

私の問題は、更新/挿入/削除を処理する方法です。挿入/更新/削除が発生するたびにモデルに通知されるように、それぞれに 1 つのトリガーがあります。トリガーは、影響を受けるエントリの ID (主キー) もモデルに伝えます。

私の最初のバージョンでは、各トリガーの後にモデルを完全にリセットしました。これはそれほど高速ではありませんでしたが、十分に高速でした。問題は、ユーザーが 1 つまたは複数の行を選択した場合、選択が失われることでした。

モデルの基本クラス (wxDataViewVirtualListModel) には、変更が発生したときに呼び出されるメソッドが含まれています。

  • RowInserted (行)
  • RowDeleted (行)
  • RowChanged (行)

それらを使用すると、選択の問題は解決されますが、問題があります。

  • 変更された行が現在フィルター処理されているセット内にあるかどうかを知るにはどうすればよいですか?
  • リスト ビューのどの行が影響を受けたかを知るにはどうすればよいですか?

最初の問題は、エントリがセットに属しているかどうかを確認するメソッドを作成することで解決できます。SQL 条件とまったく同じように動作する必要がありますが、実行可能です。

2番目の問題は、解決方法がまったくわかりません。

ビューを強制的に更新するために偽の(0または最後の行)行番号を使用しましたが、問題は、選択の前に行が挿入/削除された場合、選択が後で間違った行を指している場合などです。

どうしますか?メモリ内のすべてのエントリで高度なデータ構造を保持しますか?

この質問は別の質問に関連しています: 大きな結果セットを表示する

4

1 に答える 1

1

これを 2 つの異なる SELECT 操作に基づいて設計します。1 つはすべての行の主キーと (INSERT / UPDATE の) タイムスタンプのみを取得し、もう 1 つは 1 ページの行のすべてのデータを取得します。最新のマシンでは、主キーとタイムスタンプの完全なリストをメモリに保持することは、数 100000 行であっても問題になりません。

フィルター基準が変更されるか、トリガーが起動されるたびに、主キーとタイムスタンプのリストを再度取得します。モデルは主キーと一致するタイムスタンプのリストを維持し、モデルと新しいリストを比較すると、どの行を挿入、無効化、または削除する必要があるかがわかります。タイムスタンプが変更されたキャッシュされた行はキャッシュから削除され、同じタイムスタンプを持つキャッシュされた行を再度取得する必要はありません。キャッシュが大きくなりすぎると、キャッシュの最も古いエントリが削除されます。

リストの選択は主キーの値で識別できるため、行が削除されていない限り、モデルの変更後に、行が完全に異なる位置にある場合でも、いつでも再選択できます。これは、順序が変更されたときに同じ行の位置を維持し、まったく異なる行を選択するよりもはるかに直感的であることがわかりました。

編集:

これは、他のデータベース クライアントからの同時データ変更に対して機能します。Firebird データベース サーバーを使用するアプリケーションに対して、この方法で実装しました。データを外部から変更できない場合、主キーとタイムスタンプの完全なリストを常に取得する必要はないかもしれません。

于 2009-05-08T11:18:47.490 に答える