1

JTableを使用して、エンティティ、属性、値(EAV)ストア(リレーショナルDBMS)から取得したエンティティの属性プロパティを表示および編集するにはどうすればよいですか?

これは多くの可能な回答がある質問であることを私は知っているので、回答する前に以下の要件を確認してください。

私はあなたがすべてを読んで理解したことを示す答えに投票することを約束します(それらが完全に愚かでない限り)。


ユーザーは次のことができる必要があります。

  1. 属性でエンティティをフィルタリング/検索

  2. 表示する属性を(列として)選択します

  3. 選択した属性でエンティティを並べ替える

  4. 属性値を編集する

  5. 選択したエンティティに対して操作を実行します

  6. (オプション)後で使用するためにビューを保存する機能。


システム要求:

  1. エンティティの数:10万以上の一意のエンティティにスケールアップする必要があります

  2. 属性:ユーザーは新しい属性を追加および定義できます。システムはこれを処理できる必要があります

  3. 基盤となるストレージ:H2データベース(すでに設計済み)、JDBCによる通信

  4. メモリ:すべてが収まるわけではないので、どういうわけかDBMSクエリからプルする必要があります

  5. パフォーマンス:DBMSに必要なクエリの数を最小限に抑える必要があります(属性ごとに1つのクエリでOK、テーブルビューごとに1つのクエリを持つフォームがありますが、それはひどいです)。

  6. クエリ:検索/フィルターに一致するエンティティのリストを生成するには、1つのクエリが必要です。そうでなければ、大規模なパフォーマンスは最悪です。

  7. データの再利用:列が追加されたときにリスト全体を再クエリまたは再ソートする必要はありません。


私が見たもの:

  1. 艶をかけられたリストライブラリ

    • 長所:

      • カラムの取り扱いに柔軟に対応
      • エンティティの並べ替え/フィルターの実装が簡単
      • 列の表示形式と編集に柔軟に対応
    • 短所:

      • エンティティごとに1つのオブジェクト(オブジェクトが複雑な場合、メモリのオーバーヘッドは重大なメモリの問題になります!)
      • すべての機能を担当するオブジェクト...ただし、オブジェクトはメモリ上の理由から単純である必要があります
      • すべてのエンティティオブジェクトに対してHashMapを使用せずにユーザーが選択可能な列をサポートするにはどうすればよいですか?
  2. AbstractTableModelを拡張して、JDBC ResultSetから行、列にデータをマップします

    • 長所:
      • 結果のページングにより、メモリの問題が回避されます
      • 検索/フィルタリングはSQLで直接行われます
      • メモリに優しい、行ごとにオブジェクトを作成する必要はありません
    • 短所:
      • カスタム列の実装と並べ替えは面倒です(テーブルヘッダーレンダラー、並べ替え列と順序の管理など)。
      • おそらくカスタムJTableColumnModelも作成する必要があり、これは面倒になります。
      • SQLを頻繁に操作する必要があるため、DBスキーマが変更された場合は、複数のコードを書き直す必要があります。
      • エンティティID情報を維持するのが難しい
  3. ORM

    • 長所:
      • DB行をオブジェクトにマップするように設計されています
      • オブジェクト管理を提供します
    • 短所:
      • エンティティ-属性-値モデルの最悪のソリューション
      • DBMSとJavaコードに加えて、ORMコードを学習して作成する必要があります。
      • エンティティは任意の数の属性を持つことができます。ORMは静的で制限されたオブジェクト属性でのみ有効です
      • カスタムSQLの柔軟性/速度を失う

私が見逃したより良いオプション、またはグレーズドリストやカスタムテーブルモデルを簡単にするための賢い方法はありますか?

ORMは、EAVストレージとのマッチングが非常に悪いため、オプションとして完全に破棄しました。

4

1 に答える 1

1

あなたの最善の選択肢は、「JDBC ResultSetからのフォームマップデータを使用してAbstractTableModelを拡張する」ことだと思います。

  • Java 6 JTable にはソートのサポートが組み込まれているため、実装する必要はありません。
  • モデルを慎重に設計すれば、いくつかのスキーマの変更に耐えることができます。必要に応じて簡単に変更できるように、明確にコーディングしてください。
  • とにかく、変更を書き戻す必要があります。[保存] ボタンを使用すると、バッチ更新でパフォーマンスが向上する場合もあります。
  • TableCellEditor をオーバーライドして、デフォルトのテキスト エディターの代わりにコンボボックスを提供できます。
  • すべての編集を 1 つのテーブルで実行しようとしないでください。エントリ作成などの手段を分離している
  • 実行時に JTable に列を追加/削除できます。fireTableModelChanged() だけで、新しい列が表示されます

編集:カスタム コンポーネントを作成し、すべてのレンダリングを自分で行い、適切に配置された JTextField と JComboBox を使用して編集操作を実行するには、1 つのクレイジーなことを行います。

Edit2:あなたのコメントに基づいています。fire...() 呼び出しを行う前に、選択したアイテムの位置を保存します。ところで、呼び出しによって並べ替えや選択がリセットされるとは思いません-それで問題はありませんでした。

列を追加すると、新しい列のキー フィールドと値のみを取得できます。それらを列に表示します。次に、バックグラウンドで非表示の完全なリロードを実行し、完了したらモデルをそれに切り替えます。これは、1 つのテーブルで同時に複数の ResultSet から実際に機能しています。

その列の値が表示されないため、削除は簡単です。

編集3:

DefaultRowSorter はそれほど深くありません。レコードの再インデックス テーブルを維持します。したがって、JTable が 10 番目の行を要求すると、rowsorter はインデックス テーブルの 10 番目のエントリをチェックし、実際のモデルからその index 番目の要素を取得します。

また、モデルに同一の文字列が多数ある場合は、データベースからデータをクエリするときに、文字列から文字列への単純なマップ キャッシュを使用します。このようにして、大量の冗長 String オブジェクトをすぐに GC-d できます。

編集4:

新しいフィールドをキーから値へのマップにクエリし、プライマリ モデルにキーから値へのマップのリストを含めます。次に、必要に応じてこれらの追加のマップからプライマリ データ ソースまたはいずれかから値を返す getValue() 実装を使用します。プライマリ モデルから行のキーを検索し、それを使用して追加のマップから実際の値を取得します。(ちなみに、受け入れられた回答から得られる評判は、1日の制限の対象ではありません。)

于 2009-06-24T17:26:38.603 に答える