1

如何使用 JTable 显示和编辑从实体、属性、值 (EAV) 存储(关系 DBMS)中检索到的实体的属性属性?

我知道这是一个有很多可能答案的问题,所以请在回答之前查看我的以下要求。

我保证会投票选出表明您已经阅读并理解整件事的答案(只要它们不是完全愚蠢的)。


用户需要能够:

  1. 按属性过滤/搜索实体

  2. 选择要显示的属性(作为列)

  3. 按所选属性对实体进行排序

  4. 编辑属性值

  5. 对选定实体执行操作

  6. (可选)能够保存视图供以后使用。


系统要求:

  1. 实体数量:需要扩展到 100K+ 唯一实体

  2. 属性:用户可以添加和定义新的属性,系统应该能够处理这个

  3. 底层存储:H2 数据库(已设计),通过 JDBC 通信

  4. 内存:并非所有内容都适合,因此需要以某种方式从 DBMS 查询中提取

  5. 性能:应该尽量减少 DBMS 所需的查询数量(每个属性一个查询 OK,我有一个表单,每个表视图有 1 个查询,但它很烂)。

  6. 查询:应该需要一个查询来生成与搜索/过滤器匹配的实体列表。否则巨大的性能很糟糕。

  7. 重用数据:添加列时不必重新查询或重新排序整个列表。


我看过的东西:

  1. 釉面列表库

    • 优点:

      • 灵活的色谱柱处理
      • 易于实现实体的排序/过滤
      • 灵活的列显示格式和编辑
    • 缺点:

      • 每个实体一个对象(如果对象很复杂,内存开销将成为严重的内存问题!)
      • 负责所有功能的对象......但出于内存原因,对象应该很简单
      • 对于每个实体对象,如何在没有 HashMap 的情况下支持用户可选择的列?
  2. 扩展 AbstractTableModel 以将数据从 JDBC ResultSet 映射到行、列

    • 优点:
      • 结果分页避免了内存问题
      • 搜索/过滤直接在 SQL 中
      • 内存友好,不必每行创建一个对象
    • 缺点:
      • 实现自定义列和排序是一件痛苦的事情(表头渲染器、管理排序列和顺序等)!
      • 可能也必须编写自定义 JTableColumnModel,这会变得混乱!
      • 必须大量操作 SQL,因此如果 DB 架构发生更改,则必须重写多段代码!
      • 难以维护实体 ID 信息
  3. 甲骨文

    • 优点:
      • 旨在将数据库行映射到对象
      • 提供对象管理
    • 缺点:
      • 实体-属性-价值模型的最差解决方案
      • 除了 DBMS 和 Java 代码之外,还必须学习和编写 ORM 代码!
      • 实体可以有任意数量的属性,ORM 只适用于静态的、有限的对象属性
      • 失去自定义 SQL 的灵活性/速度

有没有我错过的更好的选择,或者有什么聪明的方法可以让 Glazed Lists 或自定义表格模型更容易?

我已经完全放弃了 ORM 作为一个选项,因为它与 EAV 存储的匹配程度非常差。

4

1 回答 1

1

我认为您最好的选择是使用“使用 JDBC ResultSet 中的表单映射数据扩展 AbstractTableModel”,因为

  • Java 6 JTable 内置了排序支持,因此您实际上不需要实现它。
  • 如果你仔细设计你的模型,你可以在一些模式变化中幸存下来。清楚地编写代码,让自己在需要时更轻松地进行更改。
  • 无论如何,您都必须写回更改。使用“保存”按钮,批量更新甚至可能有助于您的表现。
  • 您可以覆盖 TableCellEditor 以提供组合框而不是默认的文本编辑器。
  • 不要试图在一张表中进行所有编辑。具有用于条目创建等的单独方法。
  • 您可以在运行时向 JTable 添加/删除列。只需 fireTableModelChanged() 即可看到新列

编辑:我会做一件疯狂的事情来创建一个自定义组件并自己进行所有渲染并使用放置良好的 JTextField 和 JComboBox 执行编辑操作。

Edit2:根据您的评论。在执行 fire...() 调用之前保存所选项目的位置。顺便说一句,我认为该调用不会重置排序或选择-对此没有问题。

如果您添加一列,您可以只获取新列的键字段和值。在列中显示它们。然后在后台进行隐藏的完全重新加载,并在完成后将模型交换为该模型。这实际上是在一个表中同时处理多个结果集。

删除很容易,因为您不显示该列的值。

编辑3:

DefaultRowSorter 没有那么深。它为您的记录维护一个重新索引表。因此,当 JTable 请求第 10 行时,行排序器会检查索引表的第 10 个条目并从您的实际模型中检索该索引元素。

此外,如果您的模型中有许多相同的字符串,请在从数据库中查询数据时使用简单的字符串映射到字符串缓存。这样,大量冗余的 String 对象可以立即被 GC-d。

编辑4:

我会将新字段查询到键值映射中,并让我的主模型包含键值映射列表。然后,我将使用 getValue() 实现,它根据需要从这些附加映射的主数据源或主数据源返回值。我会从主模型中查找行的键,并使用它从附加映射中检索实际值。(顺便说一句。从接受的答案中获得的声誉不受每日限制。)

于 2009-06-24T17:26:38.603 回答