web-dev-qa-db-ja.com

JPAを使用してクラスをマップするときに、なぜゲッターまたはセッターに注釈を付ける必要があるのですか?

サブジェクトがすべてを言っています...これまでのところ、getterやsetterに注釈を宣言している人々の利点はわかりません。私にとって、これには注釈がクラス全体に広がるという欠点があるだけであり、それによってクラスが読みにくくなる可能性があります。

フィールドに注釈を付けると、ヘルプが必要なときに投稿するコードの量が明らかに減少します。ただし、これは小さな利点です。しかし、メソッドにアノテーションを付けることは、私にとって何の目的にもなりません。

36
Kawu

メソッドにアノテーションを付けると、JPAはメソッドを介してプロパティにアクセスします。オブジェクトの内部状態がデータベーススキーマと異なる場合に意味があります。

@Entity
public class Employee {
    private String firstName;
    private String lastName;

    @Column(name = "EMP_NAME") // Due to legacy database schema
    public String getName() {
        return fisrtName + " " + lastName;
    }

    public void setName(String name) {
        ...
    }

    ... Getters and setters for firstName and lastName with @Transient ...
}

JPA 2.0では、@Accessを使用してきめ細かいレベルでアクセスタイプを指定できます。

@Entity @Access(AccessType.FIELD)
public class Employee {
    @Access(AccessType.PROPERTY) @Column(name = "EMP_NAME")
    public String getName() { ... }
    ... other properties have field access ...
}
43
axtavt

JPAを使用してクラスをマップするときに、なぜ誰かがゲッターまたはセッターに注釈を付ける必要があるのですか?

すでに述べたように、プロパティアクセスを使用すると、必要に応じてゲッターにロジックを追加できます。

しかし、質問にはタグが付けられている hibernate なので、別の(huge)利点について説明します:プロパティアクセスにより、プロキシを初期化せずにfoo.getId()を呼び出すことができます。フィールドアクセスを使用する場合は、同じ動作は得られません。 Emmanuel Bernard氏は、このフィールドアクセスの制限について次のように説明しています。

それは残念なことですが、期待されています。これは、フィールドレベルアクセスの制限の1つです。基本的に、getId()が実際に移動してidフィールドにアクセスするだけであることを知る方法はありません。安全のためにオブジェクト全体をロードする必要があります。

つまり、プロパティアクセスを使用するとコードが読みにくくなります。たとえば、クラス全体を参照して、そこに@Transientがあるかどうかを確認する必要があります。しかし、私にとっては、利点(少なくとも hibernate を使用した場合)がこの欠点をはるかに上回っています。

関連する質問

参考文献

23
Pascal Thivent

与えられた答えは正しいです。プロパティではなくメソッドに注釈を付けると、次のようになります。

  1. @Id値としてマークされている場合にgetId()を使用して、実際にDBからロードせずにプロキシオブジェクトから外部キー値を取得する権利。

  2. データベースにない内部オブジェクトの状態を更新するゲッター/セッターを作成できます。オブジェクト内でより使いやすい内部メンバーデータに解凍するDBから圧縮状態を取得するときに、これを使用しました。セッターとゲッターは圧縮された状態を設定および取得し、DBとHibernateは圧縮されていない内部メンバーについて「認識」しません。

私が経験した1つの欠点があります。

A.セッターはかなり単純でなければなりません。 Hibernateは、メンバーのデータに直接割り当てることで達成されることを実行することを期待しています。カテゴリを設定するだけでなく、関連性を示すために関連するCategoryオブジェクトを更新する「setCategory」メソッドを使用すると、問題が発生する可能性があります。

2
Clint

APIを実装から分離しているため、getter/setterでアノテーションを使用しています。また、API部分を完全にフレームワークなしで維持し、フレームワークを切り替えたり、異なる実装を提供したりしたいのです。たとえば、現在私はspring-data-jpaを使用していますが、以下のAPIを使用すると、簡単にspring-jdbcまたはその他のフレームワークに切り替えることができます。

私がしたことは、コントローラ、リポジトリ、エンティティのインターフェースを次のように定義することでした:

public interface MyEntityController<T extends MyEntity> {
    Iterable<T> listEntities();
    T getEntity(Long id);
}

public interface MyEntityService<T extends MyEntity> {
    Iterable<T> findAll();
    T findById(Long id);
}

public interface MyEntityRepository<T extends MyEntity> {
    Iterable<T> findAll();
    T findOne(Long id);
}

// no JPA annotations here
public abstract class MyEntity {
    protected Long id;
    protected String myField;
}

次に、以下のようにMyEntityを実装し、コントローラー、サービス、およびリポジトリーの実装にMyEntityImplを使用します。

@Entity
public class MyEntityImpl extends MyEntity {
    @Id public long getId() { return id; }
    @Column public String getMyField() { return myField };
    // setters, etc
}

@Repository
public interface MyEntityRepositoryImpl extends MyEntityRepository, JPARepository<MyEntityImpl, Long> {
}

私はすでにそれをテストしました、そしてそれはうまく働きます。スーパークラスは@Entityである必要があるため、MyEntityImpl@MappedSuperclassの注釈を付けるだけでは機能しません。

0
Tarek