JOOQ поддерживает пользовательские типы данных . Это означает, что вы можете определить converter
для поля базы данных, которое затем автоматически сопоставляется с вашим пользовательским типом при загрузке. Поле базы данных по-прежнему будет String
, но сгенерированное Record
для поля будет содержать Field<EligibilityRule>
. Это означает, что вам не нужно явно хранить имя класса.
Чтобы сделать это, вы должны зарегистрировать свой конвертер в генераторе кода (взято со страницы документации выше):
<database>
<!-- Then, associate custom types with database columns -->
<forcedTypes>
<forcedType>
<!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
<userType>java.util.GregorianCalendar</userType>
<!-- Associate that custom type with your converter. -->
<converter>com.example.CalendarConverter</converter>
<!-- Add a Java regular expression matching fully-qualified columns. Use the pipe to separate several expressions.
If provided, both "expressions" and "types" must match. -->
<expression>.*\.DATE_OF_.*</expression>
<!-- Add a Java regular expression matching data types to be forced to
have this type.
Data types may be reported by your database as:
- NUMBER regexp suggestion: NUMBER
- NUMBER(5) regexp suggestion: NUMBER\(5\)
- NUMBER(5, 2) regexp suggestion: NUMBER\(5,\s*2\)
- any other form
It is thus recommended to use defensive regexes for types.
If provided, both "expressions" and "types" must match. -->
<types>.*</types>
</forcedType>
</forcedTypes>
</database>
См. Также привязку пользовательского типа данных , поддерживаемую JOOQ.
Я понимаю, что вы имеете в виду, в моем случае я не создаю новое поле базы данных для каждого перечисления, вместо этого они будут храниться в виде пары rule_type и rule_value (ключ / значение), где ключ - это имя класса и значение - это значение перечисления.
Понятно. К сожалению, я не думаю, что было бы возможно сделать это безопасным для типов способом. Я считаю, что этот ответ в значительной степени соответствует тому, что вы спрашиваете - привязка специального типа, основанная на значении столбца.
Однако, поскольку вы используете перечисления, вы не можете заставить их расширять суперкласс, как в ответе выше (поскольку все перечисления неявно расширяют java.lang.Enum
, а Java не поддерживает множественное наследование). Тем не менее, вы можете попытаться немного реорганизовать свой код и сделать так, чтобы все ваши перечисления реализовывали некоторый интерфейс, то есть:
enum ProductEligibility implements Rule {...};
enum CountryEligibility implements Rule {...};
С Rule
:
interface Rule { String getRuleType(); String getRuleValue(); }
А затем создайте конвертер, как в примере на странице документов или в отдельном связанном ответе.
Конечно, это также означает, что ваши Record
будут иметь поле Field<Rule>
, а не конкретный тип перечисления. Если это приемлемо для вас, это может быть возможным вариантом.
Я не получил эту часть, Of course, this also means that your Records would have a Field<Rule> field in them, not the specific type of the enum.
. Означает ли это, что я все еще буду хранить два поля в db, rule_type и rule_value с CustomConverter для каждого из них?
Нет. У вас все равно будет только один конвертер типа Converter<Object, Rule>
. Этот преобразователь вернет или ProductEligibility
или CountryEligibility
, но он не сможет вернуть оба .
Итак, если в вашей таблице базы данных было что-то вроде:
eligiblity_rules
------------------
id user type value
234 223 com.foo.bar.ProductEligibility PRODUCT_Y
856 855 com.foo.bar.CountryEligibility US
Ваш конвертер будет выглядеть примерно так:
public Converter<Object, Rule> converter() {
return new Converter<Object, Rule>() {
@Override
public Rule from(Object t) {
// t here refers to the "value" db field above
if (checkIsProductEligibilityRule())
return ProductEligibility.fromValue(...);
else
return CountryEligibility.fromValue(...)
}
// Other converter methods
};
}
Таким образом, в вашем JOOQ
коде у вас будет:
EligibilityRuleRecord record = dslContext.selectFrom(ELIGIBILITY_RULE).where(...).fetchOne();
Rule rule = record.getValue();
Впоследствии, если вы хотите использовать определенный тип правила, вам понадобится проверка и приведение:
if (rule instanceof ProductEligibility) {
ProductEligibility peRule = (ProductEligibility) rule;
...
}
if (rule instanceof CountryEligibility) {
CountryEligibility ceRule = (CountryEligibility) rule;
...
}
...
Единственная причина для поля базы данных type
- выбор правильных данных. К сожалению, код Java не знает (во время компиляции), каким будет тип, поэтому вам понадобится проверка классов во время выполнения каждый раз, когда вы захотите узнать тип этого поля.