34

いつものように、Java 列挙型には対応するコードと名前の説明があります。また、そのようなフィールドを含む Java クラスには、それらが Enum として含まれます。

public enum MyEnum{
    SOMEINSTANCE(1, "test1"),
    SOMEINSTANCE(2, "test2");

    private final int code;
    private final String name;
    private MyEnum(int code, String name){
        this.code = code;
        this.name = name;
    }
    ... helper getter for code and name
}

@Entity
puclic class EnumHolder{
    private MyEnum myEnum;
}

私は JPA の初心者ですが、「myEnums」テーブルを次のようにしたいと考えています。

code int not null, name varchar(50) not null)

私のenumHolderテーブルにはmyEnumCode、myEnums テーブルを指すフィールドが必要です。

EnumType.ORDINAL と EnumType.STRING の両方をサポートする currenlty を使用するのは良い考えではないと思います。

そして別の質問です。myEnumsJavaMyEnumクラス データを使用してテーブルに入力するにはどうすればよいですか? どのようにしますか?最善のアプローチをお願いします。

PS: 私が提供できるソリューションは次のとおりです。

と namemyEnumを持つテーブルがあるとしましょう。質問に記載されているJava列挙型。テーブルにはフィールドへの参照が必要です。同意しない場合は、解決策をコメントしてください。codefieldsMyEnumenumHoldermyEnumCodemyEnum.code

@Entity
@Access(AccessType.FIELD)
public class EnumHolder {
    @Id private int id;
    @Transient private MyEnum myEnum;
    …
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public MyEnum getMyEnum() { return MyEnum; }
    public void setMyEnum(MyEnum myEnum) { this.myEnum = myEnum; }

    @Access(AccessType.PROPERTY) @Column(name="myEnumCode")
    protected int getMyEnumForDb() {
        return myEnum.getCode();
    }

    protected void setMyEnumForDb(int enumCode) {
        myEnum = MyEnum.getByCode( enumCode);
    }
…
}

もちろん、ここには欠点があります。しかし、現時点では、より良いアプローチが見えません。EnumType.ORDINAL および EnumType.STRING の代替は提供しないでください。その使用法に存在する可能性のあるすべての問題をここに書きたくはありません (Effective Java では、序数の使用法について説明されています)。EnumType.STRINGを使用すると、データベースに説明を付けてdbから要求することができないため、どちらも好きではありません。

fillind データベースについて。myEnumテーブルをクリアし、各Java列挙型インスタンスに対してテーブルに挿入するスクリプトを作成することは難しくないと思います。そして、展開段階で常にそれを行います。

4

3 に答える 3

52

最善の方法は、一意の ID を各列挙型にマップして、ORDINAL と STRING の落とし穴を回避することです。列挙型をマップする 5 つの方法を概説しているこの投稿を参照してください。

上記のリンクから取得:

1&2. @列挙型の使用

@Enumerated アノテーションを使用して JPA エンティティ内で列挙型をマップするには、現在 2 つの方法があります。残念ながら、EnumType.STRING と EnumType.ORDINAL の両方に制限があります。

EnumType.String を使用する場合、列挙型のいずれかの名前を変更すると、列挙型の値がデータベースに保存されている値と同期しなくなります。EnumType.ORDINAL を使用する場合、列挙内の型を削除または並べ替えると、データベースに保存された値が間違った列挙型にマップされます。

これらのオプションはどちらも脆弱です。データベースの移行を実行せずに列挙型を変更すると、データの整合性が損なわれる可能性があります。

3. ライフサイクル コールバック

考えられる解決策は、JPA ライフサイクル コールバック アノテーション、@PrePersist および @PostLoad を使用することです。エンティティに 2 つの変数があるため、これは非常に見苦しく感じます。1 つはデータベースに格納されている値をマッピングし、もう 1 つは実際の列挙型です。

4. 一意の ID を各列挙型にマッピングする

推奨される解決策は、列挙内で定義された固定値または ID に列挙をマップすることです。定義済みの固定値にマッピングすると、コードがより堅牢になります。列挙型の順序を変更したり、名前をリファクタリングしたりしても、悪影響はありません。

5. Java EE7 @Convert の使用

JPA 2.1 を使用している場合は、新しい @Convert アノテーションを使用するオプションがあります。これには、@Converter で注釈が付けられたコンバーター クラスの作成が必要です。このクラス内で、各列挙型のデータベースに保存される値を定義します。エンティティ内で、@Convert で列挙型に注釈を付けます。

私の好み: (4番)

コンバーターを使用するのではなく、列挙型内で ID を定義することを好む理由は、適切なカプセル化です。列挙型のみがその ID を認識し、エンティティのみが列挙型をデータベースにマップする方法を認識する必要があります。

コード例については、元の投稿を参照してください。

于 2013-09-05T21:44:44.633 に答える
13

を使用して、列挙型フィールドをエンティティに追加できます@Enumerated。ここで重要なのは、ケーキを持って食べたいということです。一貫性を保つために、 または のいずれかを選択することをお勧めしEnumType.ORDINALますEnumType.STRING

どちらにも長所と短所があり、このサイトにリストされています。大きな違いは順序にある​​ようです。EnumType.ORDINAL設定した場合、列挙型を更新するときに問題が発生します。

テーブルのデザイン方法を再考することをお勧めします。文字列と整数は基本的に同じ情報 (列挙値とは何か) を格納しており、大騒ぎせずにデータベースからそれを取得できます。id上記のリンクの警告を考慮して、テーブルの主キーとして を使用し、次に列挙型を文字列または序数値として使用することをお勧めします。

于 2013-04-22T06:58:59.107 に答える