web-dev-qa-db-fra.com

Pourquoi quiconque devrait-il mettre des annotations sur les getters ou les setters lors de l'utilisation de la JPA pour mapper les classes?

Le sujet dit tout ... Je ne vois aucun avantage des personnes déclarant annotations sur les getters et/ou les setters jusqu'à présent. Pour moi, cela n'a que l'inconvénient de répandre les annotations sur la classe, ce qui peut rendre la classe plus illisible.

Mettre les annotations sur les champs réduit clairement la quantité de code à poster lorsque vous avez besoin d'aide. Ceci est juste un avantage minuscule cependant. Mais mettre des annotations sur des méthodes ne servirait aucun but pour moi.

36
Kawu

Mettre les annotations sur les méthodes oblige JPA à accéder aux propriétés via des méthodes. Il est logique lorsque l'état interne de votre objet diffère du schéma de base de données:

@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 ...
}

Dans JPA 2.0, vous pouvez spécifier le type d'accès au niveau à grain fin avec @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

Pourquoi quiconque devrait-il mettre des annotations sur les getters ou les setters lors de l'utilisation de la JPA pour mapper les classes?

Comme déjà mentionné, l'accès à l'accès à la propriété permet d'ajouter une logique dans le getter, si le besoin se pose.

Mais étant donné que la question est étiquetée hibernate , je vais mentionner un autre ( énorme ) Prestation: L'accès à la propriété permet Vous devez appeler foo.getId() sans initialiser un proxy . Vous ne pouvez pas obtenir le même comportement lors de l'utilisation d'un accès sur le terrain. Emmanuel Bernard explique cette limite d'accès sur le terrain comme suit:

C'est malheureux mais attendu. C'est l'une des limitations de l'accès au niveau du terrain. Fondamentalement, nous n'avons aucun moyen de savoir que GETID () n'allez en effet pas d'accéder au champ ID. Nous devons donc charger l'objet entier pour être en sécurité.

Donc, oui, à l'aide d'un accès de propriété rend le code plus difficile à lire, vous avez par exemple pour parcourir une classe entière à voir s'il y a des @Transient autour d'ici. Mais pour moi, le bénéfice (au moins avec hibernate ) l'emporte de loin cet inconvénient de loin.

Questions connexes

Les références

23
Pascal Thivent

Les réponses données sont correctes. Les méthodes d'annotation au lieu de propriétés vous donnent:

  1. Le droit d'utiliser getid (), s'il est marqué comme valeur @ID, pour obtenir une valeur de clé étrangère à partir d'un objet proxy sans le charger de la DB.

  2. Vous pouvez créer des getters/setters qui mettent à jour l'état d'objet interne qui ne figure pas dans la base de données. J'ai utilisé cela lors de la récupération de l'état compressé de la DB que je souhaite décompresser dans l'objet dans une donnée interne plus utilisable. Les Setters and Getters set et obtiennent l'état compressé, et la DB et Hibernate ne "savent pas" sur le membre interne non compressé.

Il y a un inconvénient que j'ai frappé:

A. Vos setters doivent être assez simples. Hibernate s'attend à ce que ceux-ci fassent ce qui serait accompli par une affectation directe à une donnée membre. Une méthode "SetCategory" qui définit non seulement une catégorie, mais met également à jour l'objet de catégorie correspondant pour montrer la relation, peut vous mettre en difficulté.

2
Clint

J'utilise des annotations sur les getters/Setters car j'ai une API séparée de la mise en œuvre et je voulais garder la partie API complètement sans cadre, me permettant de changer de frameworks ou de fournir des implémentations différentes. Par exemple, maintenant j'utilise Spring-Data-JPA, mais avec l'API ci-dessous, je peux facilement passer à Spring-JDBC ou à tout autre cadre.

Ce que j'ai fait, définissez les interfaces pour le contrôleur, le référentiel et l'entité, en tant que telle:

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;
}

Ensuite, je viens de mettre en œuvre la myentity comme suit et utilisez la myentityImpl pour les implémentations du contrôleur, du service et du référentiel:

@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> {
}

Je l'ai déjà testé et ça marche bien. Juste annoter le MyEntityImpl avec @Entity n'aurait pas fonctionné, car la superclasse devrait être une @MappedSuperclass.

0
Tarek