Наверняка многие из вас сталкивались с проблемой хранения перечислений в базе данных, возникающей при попытке реализации удобного способа работы с разного рода служебными справочниками — статусами, типами объектов и так далее.
Суть её очень проста: если хранить перечисления как сущности (
Особенно актуально это в том случае, когда поле, содержащее перечисление, аннотировано как
Однако сама идея хранения в базе данных заманчива простотой построения запросов вручную, очень ценной при отладке ПО или решении сложных ситуаций. Когда можно написать не просто
На самом деле, существует очень простое и изящное решение этой проблемы, убивающее сразу всех зайцев.
Суть её очень проста: если хранить перечисления как сущности (
@Entity
), то с ними получается крайне неудобно работать, база данных нагружается лишними запросами даже несмотря на кэширование, а сами запросы к БД усложняются лишними JOIN'ами. Если же перечисление определять как enum, то с ними становится удобно работать, но возникает проблема синхронизации с базой данных и отслеживания ошибок таковой синхронизации.Особенно актуально это в том случае, когда поле, содержащее перечисление, аннотировано как
@Enumerated(EnumType.ORDINAL)
— всё мгновенно ломается при смене порядка объявления значений. Если же мы храним значения в строковом виде — как @Enumerated(EnumType.STRING)
— возникает проблема скорости доступа, так как индексы по строковым полям менее эффективны и занимают больше места. Более того, вне зависимости от способа хранения значения поля при отсутствии в базе данных таблицы со списком допустимых значений мы никак не защищены от некорректных или устаревших данных и, как следствие, проблем.Однако сама идея хранения в базе данных заманчива простотой построения запросов вручную, очень ценной при отладке ПО или решении сложных ситуаций. Когда можно написать не просто
SELECT id, title FROM product WHERE status = 5
, а, скажем, SELECT id, title FROM product JOIN status ON status.id = product.status_id WHERE status.code = 'NEW'
— это очень ценно. В том числе и тем, что мы всегда можем быть уверены в том, что status_id
содержит корректное значение, если поставим FOREIGN KEY
.На самом деле, существует очень простое и изящное решение этой проблемы, убивающее сразу всех зайцев.