Pregunta

¿Cómo puedo usar una JTable para mostrar & amp; editar propiedades de atributos para entidades recuperadas de un almacén de entidad, atributo, valor (EAV) (un DBMS relacional)?

Sé que esta es una pregunta con muchas respuestas posibles, así que POR FAVOR mire los requisitos que tengo a continuación antes de responder.

Prometo votar las respuestas que muestren que has leído & amp; entender todo el asunto (siempre y cuando no sean totalmente tontos).


El usuario debe poder:

  1. Filtrar / Buscar entidades por sus atributos

  2. Elija qué atributos mostrar (como columnas)

  3. Ordenar entidades por atributos elegidos

  4. Editar valores de atributo

  5. Realizar operaciones en entidades seleccionadas

  6. (Opcional) Posibilidad de guardar la vista para su uso posterior.


Requisitos del sistema:

  1. Número de entidades: necesita escalar hasta 100K + entidades únicas

  2. Atributos: el usuario puede agregar y definir nuevos atributos, el sistema debería poder manejar esto

  3. Almacenamiento subyacente: Base de datos H2 (ya diseñada), comunicación por JDBC

  4. Memoria: no todo encajará, por lo que de alguna manera debe extraerse de las consultas DBMS

  5. Rendimiento: debería minimizar el número de consultas necesarias para DBMS (una consulta por atributo OK, y tengo un formulario con 1 consulta por vista de tabla, pero apesta).

  6. Consultas: se debe requerir UNA consulta para generar una lista de entidades que coincidan con una búsqueda / filtro. De lo contrario, el rendimiento masivo apesta.

  7. Reutilización de datos: no debería tener que volver a consultar o reorganizar la lista completa cuando se agrega la columna.


Cosas que he visto:

  1. Biblioteca de Listas Glaseadas

    • Pros:

      • Flexible sobre el manejo de columnas
      • Clasificación / filtro de entidades fácil de implementar
      • Flexible sobre el formato de visualización de columna & amp; edición
    • Contras:

      • Un objeto por entidad (si los objetos son complejos, la sobrecarga de memoria se convierte en un serio problema de memoria)
      • Objeto responsable de toda la funcionalidad ... pero los objetos deben ser simples por razones de memoria
      • ¿Cómo apoyo columnas seleccionables por el usuario sin un HashMap para CADA objeto de entidad?
  2. Extender AbstractTableModel para asignar datos de un conjunto de resultados JDBC a filas, columnas

    • Pros:
      • La paginación de resultados evita problemas de memoria
      • La búsqueda / filtrado está directamente en SQL
      • Amigable con la memoria, no tiene que hacer un objeto por fila
    • Contras:
      • Implementando columnas personalizadas & amp; ¡ordenar es un problema (renderizador de encabezado de tabla, gestión de columnas de clasificación y orden, etc.)!
      • Probablemente también tenga que escribir JTableColumnModel personalizado, ¡y esto se vuelve desordenado!
      • Tiene que manipular mucho SQL, así que si el esquema de DB cambia, ¡tiene que reescribir múltiples piezas de código!
      • Información de ID de entidad difícil de mantener
  3. ORM

    • Pros:
      • Diseñado para asignar filas DB a objetos
      • Proporciona gestión de objetos
    • Contras:
      • PEOR POSIBLE solución para el modelo de entidad-atributo-valor
      • Tienes que aprender & amp; escribir código ORM además de DBMS & amp; Código Java!
      • Las entidades pueden tener cualquier número de atributos, ORM solo es bueno con atributos de objeto estáticos y limitados
      • Perder flexibilidad / velocidad de SQL personalizado

¿Hay alguna opción mejor que me haya perdido, o alguna forma inteligente de facilitar las Listas esmaltadas o el Modelo de tabla personalizado?

Ya he descartado totalmente ORM como una opción, debido a lo mal que coincide con el almacenamiento EAV.

¿Fue útil?

Solución

Creo que su mejor opción es ir con 'Extender AbstractTableModel con datos de mapa de formulario de un conjunto de resultados JDBC' porque

  • Java 6 JTable ha incorporado soporte de clasificación, por lo que realmente no necesita implementar eso.
  • Si diseñas tu modelo con cuidado, podrías sobrevivir a algunos cambios de esquema. Codifique claramente para permitirle hacer cambios más fáciles si lo necesita.
  • Tendrás que escribir los cambios de todos modos. Use el botón 'Guardar' y la actualización por lotes podría incluso ayudar a su rendimiento.
  • Puede anular TableCellEditor para proporcionar un cuadro combinado en lugar del editor de texto predeterminado.
  • No intentes hacer todas las ediciones en una tabla. Tener medios separados para la creación de entradas, etc.
  • Puede agregar / eliminar columnas a JTable en tiempo de ejecución. Simplemente fireTableModelChanged () y la nueva columna se vuelve visible

Editar: Una locura que haría para crear un componente personalizado y hacer todo yo mismo y realizar las operaciones de edición con JTextField y JComboBox bien ubicados.

Edit2: Basado en tu comentario. Guarde la posición del elemento seleccionado antes de realizar la llamada de disparo ... (). Por cierto, no creo que la llamada restablezca la clasificación o la selección, no tuve ningún problema con eso.

Si agrega una columna, podría obtener el campo clave y los valores solo para la nueva columna. Mostrarlos en la columna. Luego, realice una recarga completa oculta en segundo plano e intercambie el modelo cuando haya terminado. Esto prácticamente funciona desde múltiples ResultSets al mismo tiempo en una tabla.

Eliminar es fácil ya que no muestra los valores para esa columna.

Edit3:

DefaultRowSorter no es tan profundo. Mantiene una tabla de reindexación para sus registros. Entonces, cuando JTable pregunta por la décima fila, el clasificador de filas verifica su décima entrada de la tabla de índice y recupera ese elemento de índice de su modelo real.

Además, si tiene muchas cadenas idénticas en su modelo, use un mapa simple de Cadena a Caché de Cadena cuando consulte los datos de la base de datos. De esta manera, las toneladas de objetos String redundantes pueden ser GC-d de inmediato.

Edit4:

Consultaría el nuevo campo en un Mapa de clave a valor y mi modelo principal contiene una lista de mapa de clave a valor. Luego, usaría una implementación getValue () que devuelve el valor de la fuente de datos primaria de estos mapas adicionales a pedido. Buscaría la clave de la fila del modelo primario y la usaría para recuperar el valor real de los mapas adicionales. (Por cierto, la reputación obtenida de las respuestas aceptadas no está sujeta al límite diario).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top