2

JPAエンティティのコンテキストでJava列挙型を単純に使用するときに発生する厄介な問題について説明したいと思います。この問題がどのように発生するかを見てみましょう。

最初のドメイン モデル:

テキスト (小説、ニュース記事など)Textを表す JPA エンティティがあるとします。JPAエンティティは次のとおりです。

@Entity
public class Text {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Version
    @Column(name = "version")
    private Integer version;

    private String content;

    @Enumerated
    @ElementCollection
    private Set<Style> styles;

    //Setters and getters omitted.

のインスタンスにはText斜体、太字などの 1 つまたは複数のスタイルを適用できます。スタイルは Java 列挙型として表されます。

まず、アプリケーションは次の列挙型で始まると仮定します。

public enum Style {
  BOLD, ITALIC
}

以下のテストでは、リレーショナル データベースに次の行を挿入します。

統合テスト:

@Test
@Rollback(value=false)
public void inEarlyLifePersist() {
    Text text =new  Text();
    text.setContent("This is my beautiful novel...");
    text.setStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
    text.persist();
}

テキスト テーブルのデータ:

# id, content, version
11, This is my beautiful novel..., 0

*text_style テーブルのデータ:*

# text, styles
11, 0
11, 1

その後、不適切な開発者が新しいスタイルを追加することを決定します:この新しい列挙型定数/値を最初のものとして配置STRIKE_THROUGHする列挙型に:Style

public enum Style {
    STRIKE_THROUGH, BOLD, ITALIC
}

そしてnew record is inserted in DB as follows

    @Test
    @Rollback(value=false)
    public void afterChangeToEnumPersist() {
        Text text =new  Text();
        text.setContent("This is my beautiful short story...");
        text.setStyles(EnumSet.of(Style.STRIKE_THROUGH, Style.BOLD));
        text.persist();
    }

テキスト テーブル:

# id, content, version
14, This is my beautiful short story..., 0

*text_style テーブル内:*

# text, styles
14, 0
14, 1

明らかに、ドメイン モデルは深刻な状態に陥っています。

私の質問は、上記の場合のように、ドメインでスペルミスを回避するための可能な戦略は何STRIKE_THROUGHですか (列挙型定数を の後 に配置する明白な解決策以外ITALIC)?

編集 1EnumType.STRING : 明らかなパフォーマンス上の理由から、データベースに文字列 (「参考文献」を参照) を格納したくないのは明らかです。

4

4 に答える 4

3

以下のように再定義する必要がありenumます。

public enum Style {
    STRIKE_THROUGH(2), BOLD(0), ITALIC(1)

    Style(int code){
      this.code=code;
    }
}

そして、 Hibernate User タイプを実装して、 code.

于 2013-09-25T11:19:51.417 に答える
1

序数よりも列挙型の名前の方が信頼できると人々が考える理由がわかりません。実際、列挙型の名前を変更する正当な理由はたくさんあります (タイプミスの修正、政治的または政治的正当性による名前の変更など)。

名前の変更と並べ替えの両方が発生し、役立つ唯一のものはテストです。残念ながら、私が考えることができる最高のテストは、どのような変更でも失敗します。幸いなことに、テストは何が起こったのかを知ることができ、簡単に修正できます。

public void testE1IsStable() {
    assertEnumUnchanged(E1.class, 4, "bec419c8380dbe9ec3b86a7023a55107");
}

public void testE2IsStable() {
    assertEnumUnchanged(E2.class, 3, "1e89e93c6cbdbb7311b814c19d682548");
}

private void assertEnumUnchanged(Class<? extends Enum<?>> enumClass, int expectedCount, String expectedHash) {
    final Object[] enumConstants = enumClass.getEnumConstants();
    if (expectedCount < enumConstants.length) {
        final Object[] shortened = Arrays.copyOf(enumConstants, expectedCount);
        assertEquals("Enum constants may be only appended! Ask balteo!",
            expectedHash, hashAsString(shortened));
        fail("An enum constant has been added! This test needs to be updated. Ask balteo!");
    } else if (expectedCount > enumConstants.length) {
        fail("Enum constants must not be removed! Ask balteo!");
    } else {
        assertEquals("Enum constants must not be reordered! If they get renamed, this test must be updated. Ask balteo!",
            expectedHash, hashAsString(enumConstants));
    }
}

private String hashAsString(Object[] enumConstants) {
    final Hasher hasher = Hashing.md5().newHasher();
    for (final Object o : enumConstants) hasher.putUnencodedChars(o.toString());
    return hasher.hash().toString();
}
于 2014-01-24T12:54:29.587 に答える
1

Enumeratedアノテーションは、 EnumTypeを指定するプロパティも認識します。との 2 種類がEnumType.ORDINALありEnumType.STRINGます。ORDINAL がデフォルトです。

したがって、次の方法で行う場合

    @Enumerated(EnumType.STRING)

DB 列に列挙名が表示されます (序数ではありません)。もちろん、列挙型の名前の変更に対して脆弱です。あなたは一度死ぬ必要がありますが、名前の方が良いと思います。

于 2013-09-25T11:45:52.587 に答える