Вообще говоря, считается ли плохой практикой разрешать пользовательские поля в базе данных для веб-приложения?
Например, я делаю веб-приложение домашнего инвентаря для своей жены, и она захочет определить свои собственные поля для различных предметов. Я планировал позволить ей создавать категории элементов и добавлять «функции» в эти категории. Объектами будут просто ключ / значение, хранящиеся в виде строк. Таким образом, если бы у нее была категория «Аудио CD», например, она могла бы добавить функции для таких вещей, как «исполнитель», «треки» и т. Д. Но в другой категории, например «мебель», она могла бы добавить функции для таких вещей, как «материал». "(дерево, пластик и т. д.). Тогда любой элемент может принадлежать к одной (или нескольким) категориям, добавляя эти функции к элементу.
Я вижу проблемы, когда поиск по этим функциям требует сравнения строк, нет проверки данных и т. Д. Следуя гибкой методологии, возможно, было бы лучше, если бы она предложила новые категории и атрибуты, и мне просто нужно было бы создавать новые таблицы. как мы идем. В моем примере это небольшая база пользователей (2 из нас), и количество созданных записей будет небольшим, так что не так уж и плохо.
Вообще говоря, как люди справляются с чем-то подобным в «реальной жизни»?
Ответы:
Когда вы начинаете переходить к «определенным пользователем полям», что часто встречается в средствах отслеживания ошибок, управления ресурсами клиентов и аналогичных бизнес-инструментах, это то, что они не подкреплены таблицей с баджиллионными полями (если они есть, то это, вероятно, проблема своя).
Вместо этого вы найдете дизайн таблицы значений атрибутов сущности и связанный инструмент администрирования для управления действительными атрибутами.
Рассмотрим следующую таблицу:
Это после того, как вы добавили несколько атрибутов. Вместо того, чтобы
attr1
притворяться, что он читаетartist
илиtracks
илиgenre
или какие-либо атрибуты, которые имеет вещь. И вместо 5, что, если это было 50. Очевидно, что это неуправляемо. Это также требует обновления модели и повторного развертывания приложения для обработки нового поля. Не идеально.Теперь рассмотрим следующую структуру таблицы:
Вы получили свою вещь с ее основными полями. У вас есть еще две таблицы. Один с атрибутами. Каждое поле представляет собой строку в
attr
таблице. И затем естьthing_attr
пара внешних ключей, относящихся обратно кthing
столу иattr
столу. И тогда у него есть поле значения, в котором вы сохраняете любое значение поля для этой сущности.И теперь у вас есть структура, в которой таблица attr может обновляться во время выполнения, и новые поля могут быть добавлены (или удалены) на лету без существенного влияния на все приложение.
Запросы немного сложнее, и валидация тоже становится более сложной (либо хриплые хранимые процедуры, либо вся клиентская часть). Это компромисс в дизайне.
Рассмотрим также ситуацию, когда однажды вам нужно будет выполнить миграцию, и вы вернетесь в приложение и обнаружите, что теперь имеется примерно полдюжины или более атрибутов, чем изначально распределенная схема. Это делает для уродливых миграций и обновлений, где таблица значений атрибутов сущности, при правильном использовании, может быть чище. (Не всегда, но может быть.)
Если вы работаете с соответствующим вариантом базы данных nosql, вы, вероятно, могли бы сделать это (обратите внимание, что соответствующим вариантом nosql для этого, вероятно, будет хранилище значений ключа, которое, ну, в общем, таблица EAV для реляционных таблиц, описанных выше) без особых проблем. Однако он поставляется со всеми компромиссами для nosql, которые подробно описаны в другом месте.
Если вы вместо этого работаете с реляционной базой данных - вам нужна схема. Динамическое добавление столбца означает, что некоторые подмножества из следующих вещей верны:
select *
а затем делаете некоторый сложный код, чтобы выяснить, каковы данные на самом деле (см . ResultSetMetaData в Java ), и затем сохраните их в карте или какой-либо другой тип данных - но не хорошие поля в коде). Это затем отбрасывает значительную часть безопасности типов и опечаток, которые вы имеете с традиционным подходом.hasdate
поле для хранения метки времени, уже определено какhasdate
логическое значение для успешного совпадения ... и ваше обновление прерывается.varchar2
противtext
и тому подобное. Ваш код для добавления столбца будет работать на MySQL, но не на Postgres, Oracle или SQL Server.delete * from students
вместо этого, но вы не можете действительно испортить базу данных плохими способами). Количество вещей, которые могут пойти не так с доступом к схеме из-за несчастного случая или стремительного роста злонамеренных действий.Это действительно сводится к «не делай этого». Если вы действительно этого хотите, воспользуйтесь известным шаблоном структуры таблицы EAV или базой данных, полностью посвященной этой структуре. Не позволяйте людям создавать произвольные поля в таблице. Головные боли просто не стоят этого.
источник
Делать это хорошо сложно.
Для одноразового приложения, такого как то, что вы планируете, вы, конечно, можете просто добавить столбец для каждого поля и предоставить пользовательский интерфейс, который делает определение поля неподготовленным пользователем более безопасным, чем предоставление им командной строки SQL. Или вы можете следовать страшному шаблону Entity-Attribute-Value , который является классическим, хотя и несколько пугающим ответом на такого рода проблемы. Создание пользовательского интерфейса для определения полей EAV обычно намного сложнее, чем для столбцов базы данных, и запросы могут быть довольно сложными, но для большого количества полей ( т. Е. Схем с очень разреженной матрицей) это может быть единственный способ получить работа сделана
источник
Я наткнулся на нечто похожее недавно.
Я сделал 2 таблицы.
Он все ваши объекты. U установить имя этого.
И тип этого объекта: - для меня доступными типами были - инвентарь, инвентарь, пункт, офис.
И обычная настройка состояла из n элементов: child или инвентарь, который также является child of office, и я использовал таблицу соединения, чтобы соединять объекты друг с другом.
Таблица настроек содержит каждое имя поля для данного конкретного типа объекта и значение в значении.
Пример свойства офиса
Расположение, телефон, время работы
И для предметов
И т.д., все эти свойства применяются вашей моделью и сохраняются в таблице настроек в виде отдельных строк (но используйте замену, а не вставку, чтобы избежать нескольких строк для одного поля)
Поэтому, когда я хочу офис, я загружаю его легко со всеми его связями и настройками, в которых находятся настройки object_I'd (запрошенные объекты)
После этого я поворачиваю все строки из настроек и все.
И в случае, если я хотел, чтобы настройка была специфичной для предмета в инвентаре (не глобального), я устанавливаю object_I'd = я из таблицы отношений object_objects и устанавливаю settings.type = ratio_setting
Надеюсь, вы понимаете, о чем я. Я попытаюсь переформатировать ответ, когда доберусь до ноутбука.
источник
Нет, это не плохая практика. Это довольно часто. В терминах ОО это называется наследованием. У вас есть базовый класс inventoryItem и два унаследованных класса AudioCD и мебель.
Вы должны решить, как инвентарь, AudioCD и мебель хранятся в базе данных.
Если easy-query наиболее важен для вас и db-space / normalization не имеет значения, вы бы реализовали схему «таблица на иерархию».
Если пространство / нормализация наиболее важны для вас, и более сложные запросы не являются проблемой, вы должны реализовать схему «таблица для типа».
Для получения дополнительной информации см. Наследование таблицы-типа-против-таблицы-иерархии-дотнет или спящий режим Java .
источник