Hibernateで@Immutable

Hibernateの@Immutable

1. 概要

この記事では、Hibernateでエンティティ、コレクション、または属性Immutableを作成する方法について説明します。

デフォルトでは、フィールドは変更可能です。つまり、フィールドの状態を変更する操作を実行できます。

2. メーベン

プロジェクトを稼働させるには、最初に必要な依存関係をpom.xmlに追加する必要があります。 そして、Hibernateを使用しているときに、対応するdependencyを追加します。


    org.hibernate
    hibernate-core
    5.2.8.Final

また、HSQLDBを使用しているため、次のものも必要です。


    org.hsqldb
    hsqldb
    2.3.4

3. エンティティへの注釈

まず、単純なエンティティクラスを定義しましょう。

@Entity
@Immutable
@Table(name = "events_generated")
public class EventGeneratedId {

    @Id
    @Column(name = "event_generated_id")
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private Long id;

    @Column(name = "name")
    private String name;
    @Column(name = "description")
    private String description;

    // standard setters and getters
}

お気づきのように、すでに@Immutableアノテーションをエンティティに追加しているので、Eventを保存しようとすると次のようになります。

@Test
public void addEvent() {
    Event event = new Event();
    event.setId(2L);
    event.setTitle("Public Event");
    session.save(event);
    session.getTransaction().commit();
    session.close();
}

次に、出力を取得する必要があります。

Hibernate: insert into events (title, event_id) values (?, ?)

アノテーションを削除しても出力は同じである必要があります。つまり、アノテーションに関係なくエンティティを追加しようとしても効果はありません。

また、EventGeneratedIdエンティティにGeneratedValueアノテーションを追加したことに注意することも重要ですが、これはエンティティを作成するときにのみ違いがあります。 これは、IDの生成戦略を指定しているためです。他の操作は、Immutableアノテーションにより、Idフィールドに影響を与えません。

3.1. エンティティの更新

これで、エンティティの保存に問題はありませんでした。更新してみましょう。

@Test
public void updateEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    event.setTitle("Public Event");
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

Hibernateは、例外をスローせずに、update操作を単に無視します。 ただし、@Immutableアノテーションを削除すると、異なる結果が得られます。

Hibernate: select ... from events where title='My Event'
Hibernate: update events set title=? where event_id=?

これにより、オブジェクトが変更可能になり(アノテーションが含まれていない場合、mutableがデフォルト値になります)、更新でそのジョブを実行できるようになります。

3.2. エンティティの削除

エンティティの削除に関しては:

@Test
public void deleteEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    session.delete(event);
    session.getTransaction().commit();
}

変更可能かどうかに関係なく、削除を実行できます。

Hibernate: select ... from events where title='My Event'
Hibernate: delete from events where event_id=?

4. コレクションの注釈

これまで、アノテーションがエンティティにどのように作用するかを見てきましたが、冒頭で述べたように、コレクションにも適用できます。

まず、Eventクラスにコレクションを追加しましょう。

@Immutable
public Set getGuestList() {
    return guestList;
}

以前と同じように、事前に注釈を追加したので、先に進んでコレクションに要素を追加しようとすると、次のようになります。

org.hibernate.HibernateException:
  changed an immutable collection instance: [com.example.entities.Event.guestList#1]

コレクションでは、コレクションの追加または削除が許可されていないため、今回は例外が発生します。

4.1. コレクションの削除

Collectionが不変であるという別のシナリオでは、削除を試みて@Cascadeアノテーションを設定するたびに、例外がスローされます。

したがって、@Immutableが存在し、削除しようとするときはいつでも:

@Test
public void deleteCascade() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='Public Event'").list().get(0);
    String guest = event.getGuestList().iterator().next();
    event.getGuestList().remove(guest);
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

出力:

org.hibernate.HibernateException:
  changed an immutable collection instance:
  [com.example.entities.Event.guestList#1]

5. XMLノート

最後に、構成は、mutable=false属性を介してXMLを使用して行うこともできます。


    
        
            
        
        
    

ただし、基本的に注釈メソッドを使用して例を実装しているため、XMLを使用して詳細を説明することはしません。

6. 結論

この簡単な記事では、Hibernateからの有用な@Immutableアノテーションと、それがデータのより良いセマンティクスと制約を定義するのにどのように役立つかを探ります。

いつものように、これらすべての例とスニペットの実装はthe GitHub projectにあります。 これはMavenベースのプロジェクトであるため、インポートと実行が簡単である必要があります。