Postgresql 使用EclipseLink在Postgres枚举上映射Java枚举

Postgresql 使用EclipseLink在Postgres枚举上映射Java枚举,postgresql,jpa,eclipselink,Postgresql,Jpa,Eclipselink,我正在使用JPA(EclipseLink实现)进行第一次尝试,我觉得自己被卡住了: 在PostgreSQL中,我有以下db模式 CREATE TYPE mood AS ENUM ( 'sad', 'happy', 'enthusiastic' ); CREATE TABLE person ( pk BIGINT PRIMARY KEY, name VARCHAR NOT NULL, mood mood NOT NULL ); CREATE SE

我正在使用JPA(EclipseLink实现)进行第一次尝试,我觉得自己被卡住了:

在PostgreSQL中,我有以下db模式

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;
这很好,因为这个插入显示了
插入到PERSON(PK,mood,name)值(3,'happy','Joe')
(将PK作为字符串提交没有任何区别。)

在JPA方面,我编写了以下类:

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();
  }
}
但是,此示例不起作用,我不知道问题是什么:

[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]
当我将table
person
的列类型更改为
varchar
并删除注释
@Convert
@ObjectTypeConverter
时,一切都正常工作


有什么想法吗?

尝试删除@Enumerated(EnumType.STRING),因为它可能会覆盖转换器设置

什么是情绪类型?这不是标准的JDBC类型,因此这就是导致错误的原因

Postgres如何要求通过JDBC绑定这种类型?看起来很奇怪,它没有自动转换varchar值。 我看了一下,它似乎以PGObject的形式返回了这个类型,所以您需要自己的自定义转换器在Java枚举和Postgres枚举之间进行转换。您还需要将converters init方法中DatabaseField上的jdbcType设置为OTHER

请在EclipseLink上记录一个bug,以便在Postgres平台上添加对此类型的支持


我认为禁用参数绑定也会起作用。

为什么要使用
@ObjectTypeConverter
,您可以使用eclipse链接即时映射枚举,如图所示
@Enumerated
是JSR-220的一部分,而
@ObjectTypeConverter
是JSR-220的专有扩展


这是我目前正在使用的实现。但这需要
mood
列是varchar/text/String类型。在postgresql中将枚举表示为字符串没有什么错。我一直在想/希望使用枚举类型可以使选择/加入它们的速度比选择/加入char-types更快。首先,我可能会利用对象关系映射器提供的功能。然后转到本机查询或使用数据库优化。不幸的是,这没有什么区别。这是一个用户(me)定义的枚举。基本上与Java
enum
相同,但在数据库端。所以我的问题实际上是,如何将这个用户定义的数据库类型映射到用户定义的Java枚举。基本上与本问题相同,但使用Eclipse/Link而不是Hibernate。我已经找到了
Converter
-接口,但我并不真正了解如何实现它。您真的不需要转换器。这些示例有点过时。要使用转换器,您需要实现自己的转换器类。从打印数据库返回的值开始,然后需要从和转换为该值。
@Enumerated(EnumType.STRING)
@Column(name = "mood")
private Mood mood;