Mapping Java enum on Postgres enum with EclipseLin

2020-03-30 03:04发布

I am making first attempts with JPA (EclipseLink implementation) and feel quite stuck:

In PostgreSQL I have the following db schema

CREATE TYPE mood AS ENUM ( 'sad', 'happy', 'enthusiastic' );

CREATE TABLE person (
  pk      BIGINT   PRIMARY KEY,
  name    VARCHAR  NOT NULL,
  mood    mood     NOT NULL
);

CREATE SEQUENCE person_pk_seq INCREMENT BY 100 MINVALUE 100;

Which works pretty fine, as this insert shows INSERT INTO PERSON (PK, mood, name) VALUES (3, 'happy', 'Joe') (Committing the pk as String makes no difference.)

On the JPA side I wrote the following class:

package testdb;
import java.io.Serializable;
import javax.persistence.*;
import org.eclipse.persistence.annotations.*;

@Entity
public class Person implements Serializable {
  private static final long serialVersionUID = 1L;

  public enum Mood {
    sad, happy, enthusiastic;
  }

  @Id
  @SequenceGenerator(
    name="PERSON_PK_GENERATOR",
    sequenceName="PERSON_PK_SEQ",
    allocationSize = 100
  )
  @GeneratedValue(
    strategy=GenerationType.SEQUENCE,
    generator="PERSON_PK_GENERATOR"
  )
  public Long pk;

  @Enumerated( EnumType.STRING )
  @Column( name = "mood" )
  @ObjectTypeConverter( name = "moodConverter", objectType = Mood.class,
    dataType = String.class, conversionValues = {
      @ConversionValue( objectValue = "sad", dataValue = "sad" ),
      @ConversionValue( objectValue = "happy", dataValue = "happy" ),
      @ConversionValue( objectValue = "enthusiastic", dataValue = "enthusiastic" )
  })
  @Convert( "moodConverter" )
  public Mood mood;

  @Column( name = "name" )
  public String name;

  public static void main(String[] args) {
    EntityManagerFactory factory = Persistence.createEntityManagerFactory("TestDb.jpa.tests" );
    EntityManager em = factory.createEntityManager();

    em.getTransaction().begin();
    Person p = new Person();
    em.persist( p );
    System.out.println(p.pk);
    p.name = "Joe";
    p.mood = Mood.enthusiastic;
    em.getTransaction().commit();

    Query q = em.createQuery( "select p from Person p" );
    Person x = (Person)q.getResultList().get(0);
    System.out.println( x.pk + " :: " +x.mood );

    em.close();
  }
}

However, this example is not working and I have no clue what the problem is:

[EL Warning]: 2012-06-05 15:28:20.646--UnitOfWork(845463623)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.BatchUpdateException: Batch-Eintrag 0 INSERT INTO PERSON (PK, mood, name) VALUES ('801', 'enthusiastic', 'Joe') wurde abgebrochen.  Rufen Sie 'getNextException' auf, um die Ursache zu erfahren.
Error Code: 0
Call: INSERT INTO PERSON (PK, mood, name) VALUES (?, ?, ?)
    bind => [3 parameters bound]

When I alter the column type of table person to varchar and remove the annotations @Convert and @ObjectTypeConverter everything is working as expected, as well.

Any ideas?

3条回答
够拽才男人
2楼-- · 2020-03-30 03:06

Try removing the @Enumerated( EnumType.STRING ) as it might be overriding the converter settings.

查看更多
Summer. ? 凉城
3楼-- · 2020-03-30 03:17

What is the mood type? This is not a standard JDBC type, so this is the reason for your error.

How does Postgres require this type to be bound through JDBC? It seems odd it does not auto convert varchar values. I did a little looking, and it seems to return this type as PGObject, so you will need to own custom Converter that converts between your Java enum, and a Postgres enum. You will also need to set the jdbcType on the DatabaseField in your converters init method to OTHER.

Please log a bug on EclipseLink to have support added to the Postgres platform for this type.

I think disabling parameter binding would also work.

查看更多
Evening l夕情丶
4楼-- · 2020-03-30 03:19

Why do you use a @ObjectTypeConverter, you can map Enumerations out of the box with eclipse link as shown here. @Enumerated is part of JSR-220 whereas @ObjectTypeConverter is a proprietary extension from EclipseLink JPA Extensions.

@Enumerated(EnumType.STRING)
@Column(name = "mood")
private Mood mood;
查看更多
登录 后发表回答