Présentation de Spring Data Neo4j

1

Dans un précédant article je vous ai présenté la base de données Neo4j ainsi que son API standard. Vous avez pu remarquer qu’il n’est pas facile d’implémenter un dao sur cette base dans vos projets. Exemple : les nœuds et les relations ne sont pas typés. Mais la communauté Spring a sorti il y a plus d’an un autre module pour son framework Spring Data. Il va nous permettre, dans le même principe que JPA, de mapper nos entités avec la base de données Neo4j.

Présentation

Le mapping des entités ce fait grâce à des annotations spécifique à Neo4j. Si on reprend l’exemple de mon précédant article nous pouvons modéliser nos utilisateur avec un simple POJO annoté :

Ici l’annotation NodeEntity indique au framework que cette classe est une entité Neo4j. Chaque nœud doit avoir un id unique. Il est donc obligatoire, comme pour JPA d’annoter un attribut qui représentera cet id avec l’annotation @GraphId.

Grâce au template Neo4j fourni, nous allons tester l’insertion de nœud dans la base de données. Mais avant cela il faut configurer Spring pour lui indiquer ou sera stockés les fichiers de la base de données. Voici le fichier xml de configuration :

Maintenant nous pouvons écrire notre premier test :

Une autre classe bien pratique qui s’appelle Neo4jHelper nous propose de supprimer le contenu de notre base de données. Dans l’exemple elle sert à supprimer le contenu de la base avant chaque transaction. D’ailleurs ces transactions sont obligatoires pour persister dans la base de données.

Pour récupérer facilement nos utilisateurs en fonction de leur nom par exemple, nous allons indexer l’attribut « name » avec l’annotation Index :

Et de même voici le test :

Ici on récupère un repository fourni par Spring qui propose des méthodes de type DAO pour manipuler nos entités. Et grâce à la méthode findByPropertyValue qui prend en paramètre le nom de l’attribut annoté par un index et la valeur à rechercher, nous pouvons récupérer facilement nos objets.

Maintenant nous allons mettre en place les relations entre nos utilisateurs. Elles sont représentées par une collection d’utilisateurs. Il existe deux manières de déclarer cette collection : si vous en voulez une en lecture seule alors il faut utiliser un objet de type Iterable ou sinon il faut la déclarer en tant qu’objet de type Set. Ensuite il suffit de l’annoter avec @RelatedTo qui prend en option le type de la relation, le type de la classe ciblée, et la direction. Voici l’exemple :

Et son test associé :

Par default, comme pour JPA, la collection n’est pas chargée lors de la récupération puisque c’est du mode Lazy. C’est pour ça qu’il faut la charger avec le template.

Le repository GraphRepository nous fournit pas mal de méthodes pour manipuler nos entités, mais nous allons l’étendre, ou plutôt le compléter en lui ajoutant d’autres méthodes. Par exemple on pourrait ajouter le service de mon précédant article, qui permettait à l’utilisateur de savoir quels amis ont au moins deux amis en commun avec lui.

Pour rajouter ce service nous allons déclarer une interface qui contiendra sa signature avec une autre méthode qui nous facilitera l’ajout d’utilisateur :

Ensuite nous allons créer une autre interface qui représentera nos services personnalisés avec les services de base du framework :

Après implémentons nos services (Attention vous devez respecter le pattern nom_de_l’interface + impl au niveau du nom de votre classe sinon l’injection ne fonctionne pas):

La méthode findAllByTraversal prend en paramètre le nœud de départ et une description de la traversée. Dans cette description je créé un Evaluator qui indique si l’on inclut ou non le nœud traversé, et je renseigne le type et la direction des relations à traverser. Puis dans cet Evaluator je teste si le nœud qui en train d’être traversé possèdent un nombre de relations supérieures ou égales au nombre passé en paramètre de mon service. Pour finir il ne faut pas oublier d’exclure le premier nœud qui correspond au départ, plus précisément à l’utilisateur passé en paramètre de notre service.

Et pour finir voici les tests de notre repository :

On peut remarquer que grâce à l’Autowired notre interface SocialRepository nous fournit nos services plus ceux qui sont par default. Le framework route automatiquement la bonne implémentation en fonction de la méthode appelée.

Conclusion

Le concept des bases de données graphe n’est pas facile à prendre en main, surtout pour quelqu’un qui a l’habitude de travailler avec une API comme JPA. Mais Spring Data Neo4j simplifie grandement cette approche grâce aux annotations et aux templates. D’ailleurs vous pouvez coupler l’API JPA avec Spring Data Neo4j pour stoker une partie de vos entités dans une base de données et l’autre dans Neo4j.

Si vous voulez approfondir ce framework, je vous conseille de lire ce livre gratuit disponible à cette adresse : http://spring.neo4j.org/guide, et je vous assure qu’il y a encore plein de fonctionnalités à découvrir…

Code source

Voici le code source de l’exemple avec les dépendances Maven : Example source code

Partagez cet article.

A propos de l'auteur

Un commentaire

  1. Bonjour.
    Exemple très sympa et abordable.
    Par contre la partie repository en test unitaire ne passe pas dans mon cas.
    « Unable to lock store C:…targetneo4j-dbneostore, this is usually a result of some other Neo4j kernel running using the same store. »

    Si quelqu’un trouve la solution, qu’il la poste en commentaire pour le bonheur de tous :)
    Merci encore.

Ajouter un commentaire