Сопоставление Java Enum в Postgresql с Spring Data JDBC

Я хочу иметь возможность сопоставить перечисление, объявленное в java, с перечислением, созданным в postgres. Например, имея следующее:

CREATE TYPE EYE_COLOR AS ENUM ('BROWN', 'BLUE', 'GREEN');
CREATE TABLE PERSON (
    ID       INT PRIMARY KEY AUTO_INCREMENT,
    NAME     NVARCHAR2(128) NOT NULL,
    EYE      EYE_COLOR
);

В java у меня есть что-то вроде этого:

public enum EyeColor {
    BROWN,
    BLUE,
    GREEN
}
public class Person {
    @Id
    Long id;
    String name;
    EyeColor eye;
}

Когда я пытаюсь что-то сохранить в базе данных, например:

personRepository.save(new Person("test", EyeColor.BROWN))

журнал sql выглядит нормально:

Executing prepared SQL statement [INSERT INTO person (name, eye) VALUES (?, ?)]
 o.s.jdbc.core.StatementCreatorUtils      : Setting SQL statement parameter value: column index 1, parameter value [test], value class [java.lang.String], SQL type 12
 o.s.jdbc.core.StatementCreatorUtils      : Setting SQL statement parameter value: column index 2, parameter value [BROWN], value class [java.lang.String], SQL type 12

но внутри фактического поля базы данных я получаю текст исключения:

org.h2.jdbc.JdbcSQLException: General error: "java.lang.RuntimeException: type=25" [50000-196]  
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)     
at org.h2.message.DbException.get(DbException.java:168)     
at org.h2.message.DbException.convert(DbException.java:295)     
at org.h2.message.DbException.toSQLException(DbException.java:268)  
at org.h2.message.TraceObject.logAndConvert(TraceObject.java:352)   
at org.h2.jdbc.JdbcResultSetMetaData.getColumnClassName(JdbcResultSetMetaData.java:376)     
at com.intellij.database.remote.jdbc.impl.RemoteResultSetImpl.getObject(RemoteResultSetImpl.java:1269)  
at com.intellij.database.remote.jdbc.impl.RemoteResultSetImpl.getCurrentRow(RemoteResultSetImpl.java:1249)  
at com.intellij.database.remote.jdbc.impl.RemoteResultSetImpl.getObjects(RemoteResultSetImpl.java:1229)     
at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)     
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    
at java.lang.reflect.Method.invoke(Method.java:498)     
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:346)  
at sun.rmi.transport.Transport$1.run(Transport.java:200)    
at sun.rmi.transport.Transport$1.run(Transport.java:197)    
at java.security.AccessController.doPrivileged(Native Method)   
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)  
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)     
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)     
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)     
at java.security.AccessController.doPrivileged(Native Method)   
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)  
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)  
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)  
at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.RuntimeException: type=25

Если я заменю тип EYE_COLOR на NVARCHAR2 (128) в определении столбца postgres, все будет работать нормально. Вставляется фактическое значение "BROWN".

Любые идеи, как это должно быть реализовано?

LE: Забыл добавить драйвер базы данных Spring:

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:file:path/to/file;DB_CLOSE_DELAY=-1;MODE=PostgreSQL;AUTO_SERVER=TRUE

Я также пытался использовать определение ENUM, как говорится в спецификациях драйвера H2, непосредственно внутри определения столбца, но это все равно не сработало:

CREATE TABLE PERSON (
     ID       INT PRIMARY KEY AUTO_INCREMENT,
     NAME     NVARCHAR2(128) NOT NULL,
     EYE      ENUM ('BROWN', 'BLUE', 'GREEN')
);

person Razvan S    schedule 07.11.2018    source источник
comment
Он записывает исключение в поле? Это странно.   -  person Jens Schauder    schedule 07.11.2018
comment
Stacktrace везде говорит h2, но ваш тег говорит postgresql. Так что это?   -  person Jens Schauder    schedule 07.11.2018
comment
Я отредактировал ответ и добавил данные о моем водителе.   -  person Razvan S    schedule 07.11.2018
comment
jira.spring.io/browse/DATAJDBC-239 кажется связанным. Тем более, что обработка его как строки в порядке: update" title="перечисления java postgres, как заставить их работать вместе для обновления"> stackoverflow.com/questions/40356750/   -  person Jens Schauder    schedule 07.11.2018
comment
Спасибо за быстрый ответ, пока мы будем использовать строковое решение.   -  person Razvan S    schedule 07.11.2018
comment
Я предполагаю, что вы используете h2 для тестирования и postgres в производстве. В этом случае я рекомендую перейти на Testcontainers.   -  person Jens Schauder    schedule 04.06.2020


Ответы (1)


В настоящее время нет специальной поддержки перечислений Postgres в Spring Data JDBC.

Но, как описано здесь: https://stackoverflow.com/a/40356977/66686 перечислениям Postgres потребуется специальный синтаксис SQL. чтобы манипулировать.

Это позволяет предположить следующие варианты решения проблемы:

  1. используйте VARCHAR вместо ENUM в базе данных
  2. используйте аннотированный метод @Query, используя специальный синтаксис для перечисления. Это возможно только в том случае, если ваш агрегат состоит только из одного объекта.
person Jens Schauder    schedule 04.06.2020