jpa 使用EclipseLink将Java枚举Map到Postgres枚举

gstyhher  于 2022-11-14  发布在  Eclipse
关注(0)|答案(4)|浏览(200)

我第一次尝试使用JPA(EclipseLink实现),感觉非常困难:
在PostgreSQL中,我有以下数据库模式

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;

这非常好用,因为这个插入显示INSERT INTO PERSON (PK, mood, name) VALUES (3, 'happy', 'Joe')(将pk作为String提交没有区别。)
在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]

当我将表person的列类型更改为varchar并删除注解@Convert@ObjectTypeConverter时,一切都按预期运行。
有什么想法吗?

pengsaosao

pengsaosao1#

为什么要使用@ObjectTypeConverter,您可以使用eclipse链接Map开箱即用的枚举,如下所示。@Enumerated是JSR-220的一部分,而@ObjectTypeConverter是EclipseLink JPA扩展的专有扩展。

@Enumerated(EnumType.STRING)
@Column(name = "mood")
private Mood mood;
bbmckpt7

bbmckpt72#

尝试移除@Enumerated(EnumType.STRING),因为它可能会覆写转换程式设定。

yeotifhr

yeotifhr3#

什么是情绪类型?这不是一个标准的JDBC类型,所以这就是错误的原因。
Postgres是如何要求通过JDBC绑定此类型的?奇怪的是,它没有自动转换varchar值。我做了一些检查,它似乎将此类型返回为PGObject,因此您需要自己的自定义转换器,用于在Java枚举和Postgres枚举之间进行转换。您还需要在转换器的init方法中将DatabaseField上的jdbcType设置为OTHER。
请在EclipseLink上记录一个错误,以便将此类型的支持添加到Postgres平台。
我认为禁用参数绑定也可以。

wb1gzix0

wb1gzix04#

我迟到了10年但是...
stringtype=unspecified添加到连接字符串中即可。
我使用的连接字符串如下:
jdbc:postgresql://localhost:5432/mydatabase?stringtype=unspecified
然后,所有用@Enumerated(STRING)标注的字段都自动转换为pg枚举类型。

相关问题