Java Enums,JPA和Postgres枚举 - 如何让它们协同工作?

Jas*_*oor 32 java postgresql jpa

我们有一个postgres数据库与postgres枚举.我们开始在我们的应用程序中构建JPA.我们还有Java枚举,它反映了postgres枚举.现在最大的问题是如何让JPA一方面理解Java枚举,另一方面知道postgres枚举?Java方面应该相当容易,但我不知道如何做postgres方面.

Arj*_*jms 22

这涉及制作多个映射.

首先,JDBC驱动程序将Postgres枚举作为PGObject类型的实例返回.它的type属性具有postgres枚举的名称,value属性具有其值.(但序数并未存储,因此从技术上讲,它不再是枚举,因此可能完全没用)

无论如何,如果你在Postgres中有这样的定义:


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

然后结果集将包含一个PGObject,其类型为"mood",值为"happy",表示具有此枚举类型的列和值为"happy"的行.

接下来要做的是编写一些拦截器代码,它位于JPA从原始结果集读取的位置和设置实体上的值之间.例如,假设您在Java中有以下实体:


public @Entity class Person {

  public static enum Mood {sad, ok, happy}

  @Id Long ID;
  Mood mood;

}

不幸的是,JPA没有提供一个简单的拦截点,您可以在其中执行从PGObject到Java enum Mood的转换.然而,大多数JPA供应商都有一些专有支持.例如,Hibernate具有TypeDef和Type注释(来自Hibernate-annotations.jar).


@TypeDef(name="myEnumConverter", typeClass=MyEnumConverter.class)
public @Entity class Person {

  public static enum Mood {sad, ok, happy}

  @Id Long ID;
  @Type(type="myEnumConverter") Mood mood;

这些允许您提供实际转换的UserType实例(来自Hibernate-core.jar):


public class MyEnumConverter implements UserType {

    private static final int[] SQL_TYPES = new int[]{Types.OTHER};

    public Object nullSafeGet(ResultSet arg0, String[] arg1, Object arg2) throws HibernateException, SQLException {

        Object pgObject = arg0.getObject(X); // X is the column containing the enum

        try {
            Method valueMethod = pgObject.getClass().getMethod("getValue");
            String value = (String)valueMethod.invoke(pgObject);            
            return Mood.valueOf(value);     
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public int[] sqlTypes() {       
        return SQL_TYPES;
    }

    // Rest of methods omitted

}

这不是一个完整的工作解决方案,而只是一个快速指针,希望是正确的方向.

  • >我们现在也将我们的系统移动到JPA,但是我们将java枚举映射到varchar列仍然没有问题,Hibernate varchars在数据库中看起来不错,但是与DB中的实际枚举相比,你错过了两件事:*类型安全,除非您要为每个列添加检查约束,或者将FK用于将所有varchar值保存为PK的单独表.*速度.字符串查找和比较速度较慢,即使在索引时也是如此.无论如何它是一个权衡.要么使用varchars,除了上述限制,要么使用本机PG枚举并接受非自动映射. (2认同)

小智 19

我实际上使用的方法比使用PGObject和Converters的方式更简单.因为在Postgres中,enum很自然地转换为文本,所以你只需要让它做它最擅长的事情.如果他不介意的话,我会借用Arjan的情绪例子:

Postgres中的枚举类型:

CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
Run Code Online (Sandbox Code Playgroud)

Java中的类和枚举:

public @Entity class Person {

  public static enum Mood {sad, ok, happy};

  @Enumerated(EnumType.STRING)
  Mood mood;
Run Code Online (Sandbox Code Playgroud)

}

@Enumerated标记表示枚举的序列化/反序列化应该在文本中完成.没有它,它使用int,这比任何东西都麻烦.

此时您有两种选择.你要么:

  1. stringtype = unspecified添加到连接字符串,如JDBC连接参数中所述.这让Postgres猜测右侧类型并充分转换所有内容,因为它收到类似'enum = unknown'的内容,这是一个表达式,它已经知道该怎么做(将?值提供给左侧类型的反序列化器).这是首选选项,因为它应该适用于所有简单的UDT,例如一次性枚举.

要么:

  1. 创建从varchar到数据库中枚举的隐式转换.所以在第二种情况下,数据库接收一些赋值或比较,如'enum = varchar',它在其内部目录中找到一条规则,说它可以通过varchar的序列化函数传递右手值,然后是反序列化函数.枚举.这比我们需要的步骤更多; 并且在目录中有太多隐式强制转换可能导致任意查询具有模糊的解释,因此请谨慎使用它.演员创作是:

    创建CAST(字符变化为情绪),而不是隐含的;

应该只是这样.

  • 这是迄今为止最近实现的最简单选项. (7认同)