Если в jmix использовать динамически Map<String, Object> attr в jsonb для psql, если да как я могу это сделать скажите плз?)
Добрый день,
Jmix из коробки не поддерживает jsonb
, тк такой тип не является кроссплатформенным для разных СУБД
. Однако, добавить его не сложно в проект.
Первый способ:
-
Создаем
changeset
, держим в голове, что не все СУБД поддерживает такой тип колонки:<changeSet id="1" author="jsonbtest"> <addColumn tableName="USER_"> <column name="LOCATION" type="jsonb" defaultValue="{}"/> </addColumn> </changeSet>
Просто добавляем колонку с типом jsonb.
-
Добавляем в проект DTO JsonB дженерик типа:
@JmixEntity(annotatedPropertiesOnly = true) public class JsonB { private Map<String, Object> container = new HashMap<>(); public Map<String, Object> getContainer() { return container; } public void setContainer(Map<String, Object> container) { this.container = container; } }
Здесь стоит отметить обязательность
@JmixEntity(annotatedPropertiesOnly = true)
, так мы обеспечиваем себе метаданные дляJmix
для типаJsonB
и одновременно с этим игнорируемMap<String, Object>
, чтобы оно не попало в мета данные, ведь мы сами в ручную будем ее записывать в базу (при помощиObjectMapper
будем весь класс marshal -ить в json) -
Добавляем JPA Converter:
@Converter(autoApply = true)
public class JsonbConverter implements AttributeConverter<JsonB, PGobject> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public PGobject convertToDatabaseColumn(JsonB attribute) {
PGobject result = new PGobject();
String jsonbResult;
result.setType("jsonb");
try {
jsonbResult = objectMapper.writeValueAsString(attribute);
result.setValue(jsonbResult);
} catch (Exception e) {
}
return result;
}
@Override
public JsonB convertToEntityAttribute(PGobject dbData) {
if(dbData == null || !dbData.getType().equals("jsonb") || dbData.getValue() == null){
return new JsonB();
}
try {
return objectMapper.readValue(dbData.getValue(), JsonB.class);
} catch (JsonProcessingException e) {
return new JsonB();
}
}
}
- Добавляем наш тип в любую сущность, например, User:
@Convert(converter = JsonbConverter.class)
@Column(name = "LOCATION")
private JsonB location = new JsonB();
Вот и все, теперь в проекте есть jsonb с типом Map<String, Object>. Ссылка на демо проект - GitHub - KartnDev/jsonbjmix: This is example how to use Postgres's JsonB with Jmix and JPA
Альтернативный вариант:
Альтернативный вариант вместо JmixEntity DTO можно создать JPA DateType через аннотацию, и даже можно унастледоваться от Map<String, Object> или использоваться паттерн декоратор, из за чего год будет на 1 вложенную сущность меньше (вместо выражения entity.getJsonB().getContainer().get("key")
будет entity.getJsonB().get("key")
)
С уважением,
Дмитрий