Отображение данных значения атрибута сущности в JTable?
Вопрос
Как я могу использовать JTable для отображения и редактирования свойств атрибутов для сущностей, полученных из хранилища сущностей, атрибутов, значений (EAV) (реляционная СУБД)?
Я знаю, что это вопрос с множеством возможных ответов, поэтому ПОЖАЛУЙСТА прежде чем ответить, ознакомьтесь с требованиями, которые у меня есть ниже.
Я обещаю голосовать за ответы, которые покажут, что вы прочитали и поняли все (при условии, что они не совсем глупы).
Пользователь должен иметь возможность:
Фильтрация/поиск объектов по их атрибутам
Выберите, какие атрибуты отображать (в виде столбцов)
Сортировка объектов по выбранным атрибутам
Редактировать значения атрибутов
Выполнять операции с выбранными объектами
(Необязательный) Возможность сохранить вид для последующего использования.
Системные Требования:
Количество объектов:необходимо масштабировать до 100 000+ уникальных объектов
Атрибуты:пользователь может добавлять и определять новые атрибуты, система должна иметь возможность справиться с этим
Базовое хранилище:База данных H2 (уже разработана), общающаяся через JDBC.
Объем памяти:не всё поместится, поэтому как-то надо тянуть из СУБД запросы
Производительность:следует минимизировать количество запросов, необходимых для СУБД (один запрос на атрибут — ОК, и у меня есть форма с 1 запросом на представление таблицы, но это отстой).
Запросы:Для создания списка объектов, соответствующих запросу/фильтру, должен потребоваться ОДИН запрос.В противном случае огромная производительность — отстой.
Повторное использование данных:не нужно повторно запрашивать или пересортировать весь список при добавлении столбца.
Вещи, которые я посмотрел:
Библиотека глазурованных списков
Плюсы:
- Гибкая обработка столбцов
- Легко реализовать сортировку/фильтрацию объектов
- Гибкий формат отображения и редактирования столбцов
Минусы:
- Один объект на сущность (если объекты сложные, излишек памяти становится серьезной проблемой с памятью!)
- Объект, отвечающий за всю функциональность...но объекты должны быть простыми из соображений памяти
- Как поддерживать выбираемые пользователем столбцы без HashMap для КАЖДОГО объекта сущности?
Расширение AbstractTableModel для сопоставления данных из набора результатов JDBC со строками и столбцами.
- Плюсы:
- Разбиение результатов на страницы позволяет избежать проблем с памятью
- Поиск/фильтрация осуществляется непосредственно в SQL.
- Удобен для памяти, не нужно создавать объект для каждой строки
- Минусы:
- Реализация пользовательских столбцов и сортировки — это головная боль (рендеринг заголовков таблиц, управление столбцами и порядком сортировки и т. д.)!
- Вероятно, придется также написать собственную JTableColumnModel, и это становится грязным!
- Приходится много манипулировать SQL, поэтому, если схема БД изменится, придется переписать несколько фрагментов кода!
- Трудно сохранить информацию об идентификаторе объекта.
- Плюсы:
ОРМ
- Плюсы:
- Предназначен для сопоставления строк БД с объектами.
- Обеспечивает управление объектами
- Минусы:
- НАИЛУЧШЕЕ ВОЗМОЖНОЕ решение для модели сущности-атрибута-значения
- Придется изучать и писать код ORM в дополнение к коду СУБД и Java!
- Сущности могут иметь любой количество атрибутов, ORM хорош только со статическими, ограниченными атрибутами объекта.
- Потерять гибкость/скорость пользовательского SQL.
- Плюсы:
Есть ли лучший вариант, который я пропустил, или какой-нибудь умный способ упростить глазурованные списки или пользовательскую модель таблицы?
Я уже полностью отказался от ORM как от варианта из-за того, насколько он плохо сочетается с хранилищем EAV.
Решение
Я думаю, что лучше всего использовать «Расширение AbstractTableModel с данными карты формы из набора результатов JDBC», потому что
- Java 6 JTable имеет встроенную поддержку сортировки, поэтому вам не нужно ее реализовывать.
- Если вы тщательно спроектируете свою модель, вы сможете пережить некоторые изменения в схеме.Четкий код, позволяющий вам легче вносить изменения, если вам нужно.
- В любом случае вам придется записать изменения.Используйте кнопку «Сохранить», и пакетное обновление может даже улучшить вашу производительность.
- Вы можете переопределить TableCellEditor, чтобы он предоставлял поле со списком вместо текстового редактора по умолчанию.
- Не пытайтесь внести все изменения в одну таблицу.Иметь отдельные средства для создания записей и т. д.
- Вы можете добавлять/удалять столбцы в JTable во время выполнения.Просто fireTableModelChanged() и новый столбец станет видимым.
Редактировать: Я бы сделал одну сумасшедшую вещь: создал собственный компонент, сам выполнил всю отрисовку и выполнил операции редактирования с помощью хорошо расположенных JTextField и JComboBox.
Редактировать2: Судя по вашему комментарию.Сохраните положение выбранного элемента перед вызовом fire...().Кстати, я не думаю, что вызов сбрасывает сортировку или выбор — с этим проблем не было.
Если вы добавите столбец, вы можете просто получить ключевое поле и значения только для нового столбца.Отобразите их в столбце.Затем выполните скрытую полную перезагрузку в фоновом режиме и замените модель на нее, когда она будет завершена.Практически это работает с несколькими наборами результатов одновременно в одной таблице.
Удалить легко, поскольку вы не показываете значения для этого столбца.
Редактировать3:
DefaultRowSorter не так уж и глубок.Он поддерживает таблицу переиндексации ваших записей.Поэтому, когда JTable запрашивает 10-ю строку, сортировщик строк проверяет свою 10-ю запись индексной таблицы и извлекает этот индексный элемент из вашей фактической модели.
Кроме того, если в вашей модели много одинаковых строк, используйте простую карту кэша строк в строки при запросе данных из базы данных.Таким образом, тонны избыточных объектов String можно сразу же GC-d.
Редактировать4:
Я бы запросил новое поле в карте ключа к значению, и моя основная модель содержала бы список карт ключа к значению.Затем я бы использовал реализацию getValue(), которая по запросу возвращает значение либо из основного источника данных, либо из этих дополнительных карт.Я бы искал ключ строки в основной модели и использовал его для получения фактического значения из дополнительных карт.(Кстати.Репутация, полученная за принятые ответы, не подлежит дневному лимиту.)