Charger partiellement une entité avec JPA
Il est intéressant, dans nombre de cas, de ne charger que partiellement une entité en JPA. Prennons l'exemple de JTentative, un agrégateur de flux RSS. Il est souhaitable de charger la liste des entrées appartenant à un flux, mais sans forcément charger l'intégralité de chaque entité (contenu et description sont des champs lourds et souvent inutilisés).
Plusieurs solutions existent pour charger partiellement une entité, de ne sélectionner que certains champs à charger depuis la base de données.
Première solution :
La première solution consiste à définir certains champs de notre entité avec un attribut
L'annotation
Voici un exemple de code mettant en avant cette annotation. Le code de l'entité à été réduit pour plus de lisibilité :
Cette solution présente cependant un inconvénient majeur : si elle fonctionne correctement lorsque l'on charge une entité via l'
Cette solution est basée sur un opérateur méconnu du langage JPA-QL,
Voici un autre exemple, le code de l'entité a là aussi été réduit :
Quelques précisions cependant :
Le code complet de l'entité utilisée pour cette exemple est disponible sur le dépôt SVN de JTentative.
Plusieurs solutions existent pour charger partiellement une entité, de ne sélectionner que certains champs à charger depuis la base de données.
Première solution : FetchType.LAZY
La première solution consiste à définir certains champs de notre entité avec un attribut fetch à LAZY. Cela permet de spécifier que ces champs ne sont pas chargés lors du chargement de l'entité, mais uniquement lors du premier accès à ce champ.L'annotation
@Basic nous permet de spécifier ce lazy-loading.Voici un exemple de code mettant en avant cette annotation. Le code de l'entité à été réduit pour plus de lisibilité :
@Entity
public class Entry implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private String author;
@Lob
@Basic(fetch=FetchType.LAZY)
private String description;
@Lob
@Basic(fetch=FetchType.LAZY)
private String content;
/* Getters, Setters... */
}
Cette solution présente cependant un inconvénient majeur : si elle fonctionne correctement lorsque l'on charge une entité via l'
EntityManager, elle est complètement inefficace lors de la sélection de données via une requête JPA-QL.
Seconde solution : Sélectionner uniquement les champs dont on a besoin
Une seconde solution peut-être mise en place dans une requête JPA-QL. Cependant, elle ne fonctionnera paslors de la sélection lors d'un appel à la méthodefind() de l'EntityManager.Cette solution est basée sur un opérateur méconnu du langage JPA-QL,
new. L'opérateur new permet d'intancier des objets au sein d'une requête JPA-QL. Il s'agit donc d'instancier un objet, en fournissant au constructeur uniquement les champs que nous souhaitons récupérer.Voici un autre exemple, le code de l'entité a là aussi été réduit :
@Entity
@NamedQuery(name="Entry.findAll", query="SELECT new Entry(e.id, e.title, e.author) FROM Entry AS e")
public class Entry implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private String author;
@Lob
@Basic(fetch=FetchType.LAZY)
private String description;
@Lob
@Basic(fetch=FetchType.LAZY)
private String content;
public Entry() {
}
public Entry(Long id, String title, String author) {
this.id = id;
this.title = title;
this.author = author;
}
/* Getters, Setters... */
}
Quelques précisions cependant :
- Il faut préciser la classe complète de l'entité dans la requête, incluant le nom du package
- Le constructeur que l'on souhaite invoquer doit exister
- Prennez garde avec vos entités chargées de cette manière : certaines propriétés sont absentes, une mise à jour dans la base de données avec une entité chargée partiellement risque d'effacer certaines valeurs
Le code complet de l'entité utilisée pour cette exemple est disponible sur le dépôt SVN de JTentative.
Salut,
Merci pour ce post.
Je ne connaissais pas encore @basic.
Avez-vous des liens vers des "bons" sites sur JPA ?
Wadaël
Posted by Wadael on août 24, 2009 at 02:00 PM CEST #
Quelques ressources concernant JPA, un peu en vrac :
- "The Java EE 5 Tutorial, Part V, Persistence" - Le tutoriel officiel de Sun sur JPA, très bonne introduction pour apprendre JPA
- "Xebia blog" - Une liste de Design Patterns très utiles : http://blog.xebia.com/category/jpa/implementation-patterns/
- "Hibernate", notemment les projets "Hibernate annotations" et "Hibernate EntityManager" - Une des implémentations des plus connues et des plus documentées de JPA
Il s'agit là de quelques ressources qui me viennent directement à l'esprit, il en existe bien entendu beaucoup d'autres :-)
Posted by viv on août 24, 2009 at 09:04 PM CEST #