1. ホーム

[解決済み】JPAのMap enumは固定値?

2022-04-09 10:56:38

質問

JPAを使用してenumをマッピングするためのさまざまな方法を探しています。特に、各列挙体の整数値を設定し、その整数値のみを保存したいのです。

@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {

  public enum Right {
      READ(100), WRITE(200), EDITOR (300);

      private int value;

      Right(int value) { this.value = value; }

      public int getValue() { return value; }
  };

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "AUTHORITY_ID")
  private Long id;

  // the enum to map : 
  private Right right;
}

簡単な解決策は、EnumeratedアノテーションをEnumType.ORDINALで使用することです。

@Column(name = "RIGHT")
@Enumerated(EnumType.ORDINAL)
private Right right;

しかしこの場合、JPAは私が欲しい値(100,200,300)ではなく、enumインデックス(0,1,2)をマップします。

私が見つけた2つの解決策は、簡単ではなさそうです...。

第一の解決策

解決策 ここで提案 は、@PrePersist と @PostLoad を使用して enum を他のフィールドに変換し、enum フィールドを transient としてマークします。

@Basic
private int intValueForAnEnum;

@PrePersist
void populateDBFields() {
  intValueForAnEnum = right.getValue();
}

@PostLoad
void populateTransientFields() {
  right = Right.valueOf(intValueForAnEnum);
}

第二の解決策

第二の解決策 ここで提案 は一般的な変換オブジェクトを提案しましたが、まだ重く、ハイバーネート指向のようです(@TypeはJava EEには存在しないようです)。

@Type(
    type = "org.appfuse.tutorial.commons.hibernate.GenericEnumUserType",
    parameters = {
            @Parameter(
                name  = "enumClass",                      
                value = "Authority$Right"),
            @Parameter(
                name  = "identifierMethod",
                value = "toInt"),
            @Parameter(
                name  = "valueOfMethod",
                value = "fromInt")
            }
)

他に解決策はありますか?

いくつかアイデアはあるのですが、JPAに存在するかどうかわかりません。

  • Authority オブジェクトのロードおよび保存時に、Authority クラスの右メンバのセッタおよびゲッタ・メソッドを使用する。
  • 同等の考えとして、enumをintに、intをenumに変換するためのRight enumのメソッドが何であるかをJPAに伝えることができます。
  • Springを使っているので、JPAに特定のコンバータ(RightEditor)を使うように指示する方法はないのでしょうか?

どのように解決するのですか?

JPA 2.1より前のバージョンでは、JPAは列挙型を扱うのに2つの方法しか提供していません。 name またはその ordinal . そして、標準のJPAはカスタムタイプをサポートしていません。だから

  • カスタムの型変換を行いたい場合は、プロバイダエクステンションを使用する必要があります (Hibernateで UserType 、EclipseLink Converter など)。(第二の解決策)。~or~
  • PrePersistと@PostLoadのトリックを使う必要があります(第1の解決策)。~または〜。
  • ゲッターとセッターにアノテーションを付けて int 値 ~or~
  • エンティティレベルで整数属性を使用し、ゲッターとセッターで変換を実行します。

最新のオプションを説明します(これは基本的な実装です、必要に応じて微調整してください)。

@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {

    public enum Right {
        READ(100), WRITE(200), EDITOR (300);

        private int value;

        Right(int value) { this.value = value; }    

        public int getValue() { return value; }

        public static Right parse(int id) {
            Right right = null; // Default
            for (Right item : Right.values()) {
                if (item.getValue()==id) {
                    right = item;
                    break;
                }
            }
            return right;
        }

    };

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "AUTHORITY_ID")
    private Long id;

    @Column(name = "RIGHT_ID")
    private int rightId;

    public Right getRight () {
        return Right.parse(this.rightId);
    }

    public void setRight(Right right) {
        this.rightId = right.getValue();
    }

}