martes, 3 de enero de 2012

Spring Data Neo4j

Neo4j es una base de datos basada en grafos. De la cual ya hablamos:

http://emanuelpeg.blogspot.com/2009/09/neo4j.html

Neo4j permite acceder a un nodo mediante una clave la cual contiene un valor. También tenemos una API para acceder a los datos y un lenguaje de consulta llamado Cypher.

Una de las características de Neo4j es que es una base transaccional y por lo tanto soporta ACID. Esto es bastante inusual para una base de datos NoSQL.

Podemos agregar a un estro proyecto Neo4j (si utilizamos maven) con la siguiente entrada en el pom:

  
   org.neo4j
   neo4j
   1.5
  


Trabajar con la Api de Neo4j puede ser un trabajo duro por lo tanto Spring framework nos provee un modulo que nos permite trabajar con Neo4j de forma más fácil y elegante.

Primero agregamos la siguiente entrada al pom:

 
org.springframework.data 
spring-data-neo4j 
2.0.0.RC1 
 
Y ahora vamos a agregar la siguiente entrada al applicationContext.xml :

 
... 
 
... 
 
La idea es hacer una aplicación que mantenga la relación de amistad entre personas. Primero creamos el proyecto con maven:

mvn archetype:generate

Luego configuramos como un proyecto normalito de maven.

Y el pom debería tener las siguientes dependencias:


 4.0.0

 org.assembly
 friend
 1.0-SNAPSHOT
 jar

 friend
 http://maven.apache.org

 
  UTF-8
  3.0.6.RELEASE
 

 
  
   
    maven-compiler-plugin
    
     1.6
     1.6
    
   
   
    org.apache.maven.plugins
    maven-eclipse-plugin
    2.7
    
     2.0
     true
    
   
   
    org.apache.maven.plugins
    maven-javadoc-plugin
   
   
    org.apache.maven.plugins
    maven-project-info-reports-plugin
   
  
 

 
  
   spring-snapshot
   Spring Maven SNAPSHOT Repository
   http://s3.amazonaws.com/maven.springframework.org/snapshot
  
 

 

  
   org.springframework.data
   spring-data-neo4j
   2.0.0.BUILD-SNAPSHOT
  

  
   org.springframework
   spring-core
   ${spring.version}
  

  
   org.springframework
   spring-context
   ${spring.version}
  

  
   org.springframework
   spring-aop
   ${spring.version}
  

  
   org.springframework
   spring-aspects
   ${spring.version}
  

  
   org.springframework
   spring-tx
   ${spring.version}
  

  
   org.neo4j
   neo4j
   1.5
  

  
   junit
   junit
   4.10
   test
  

  
   org.springframework
   spring-test
   ${spring.version}
   test
  


 



Luego hacen mvn clean install y luego eclipse:eclipse.

Luego importamos el proyecto a eclipse, ahora veamos la clase persona:

/**
 * 
 */
package org.assembly.model;

import java.util.HashSet;
import java.util.Set;

import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;

/**
 * @author emanuel
 *
 */
@NodeEntity
public class Person {
 
 @GraphId
 private Long id;
 
 @Indexed //nos permite buscar por ejemplo por nombre. 2 personas no deberian llamarse igual
 private String name;
 
 private String lastName;
 
 private Set friends = new HashSet();

 public Person() { }
 
 public Person(String name, String lastName) {
  super();
  this.name = name;
  this.lastName = lastName;
 }

 public Person(String name, String lastName, HashSet friends) {
  super();
  this.name = name;
  this.lastName = lastName;
  this.friends = friends;
 }

 public void makeAFriend(Person friend) {
  this.getFriends().add(friend);
  friend.getFriends().add(this);
 }
 
//geters , seters, hashcode and equal
 

}



Con esas anotaciones le decimos a spring cual es el id de nuestro nodo y que puede usar como indice para buscar. Ahora hagamos un dao:

package org.assembly.dao;
//La interfaz
import org.assembly.model.Person;

public interface PersonDAO {
 
 void save(Person person);

 Person get(Long id);
 
 Person findByName(String name);
 
}



package org.assembly.dao;

import java.util.List;

import org.assembly.model.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.Neo4jTemplate;
//La implementacion
public class PersonDAOImpl implements PersonDAO {
 
 @Autowired
 private Neo4jTemplate template;
 
 public void setTemplate(Neo4jTemplate template) {
  this.template = template;
 }

 @Override
 public void save(Person person) {
  this.template.save(person);
 }

 @Override
 public Person get(Long id) {
  return this.template.findOne(id, Person.class);
 }

 @Override
 public Person findByName(String name) {
  GraphRepository movieRepository =
    template.repositoryFor(Person.class);
  
  return movieRepository.findByPropertyValue("name", name);
 }


}



Vamos a configurar el applicationContext.xml:



 

 
  
  
 

 

 

 
  
  
 





Vamos a probar todo con un test:

package org.assembly.dao;

import static org.junit.Assert.assertEquals;

import javax.annotation.Resource;

import org.assembly.model.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class PersonDAOTest {

 @Resource
 private PersonDAO dao;
 
 public void setDao(PersonDAO dao) {
  this.dao = dao;
 }
 
 @Test 
 @Transactional
 public void save() {
  Person person = new Person("Pablo", "Goette");
  
  dao.save(person);
  
  Person personSaved = dao.get(person.getId());
  
  assertEquals(person, personSaved);
 }
 
 @Test 
 @Transactional
 public void saveFriendly() {
  Person person = new Person("Pablo", "Goette");
  
  person.getFriends().add(new Person("Mercedez","Benz"));
  person.getFriends().add(new Person("Al","Colico"));
  person.getFriends().add(new Person("Barry","Gota"));
  person.getFriends().add(new Person("Mercedez","Benz"));
  dao.save(person);
  
  Person personSaved = dao.get(person.getId());
  
  assertEquals(person, personSaved);
 }

 @Test 
 @Transactional
 public void findByName() {
  Person person = new Person("Aquiles", "Canto");
  
  dao.save(person);
  
  Person personSaved = dao.findByName("Aquiles");
  
  assertEquals(person, personSaved);
 }
}

Y listo, verán por ahí la carpeta data con la base de neo4j.


Si todo salio bien los test terminaron exitosos.

Dejo el repositorio subversion:
svn checkout http://spring-neo4j.googlecode.com/svn/trunk/ spring-neo4j-read-only

Dejo links:

http://www.springsource.org/spring-data/neo4j
http://neo4j.org/
http://video.neo4j.org/YbYN/webinar-introduction-to-spring-data-neo4j/
http://youtu.be/9qVs9vxx8lk
http://www.infoq.com/presentations/Introduction-to-Spring-Data-Neo4j

Y dejo un video:



2 comentarios:

  1. Thank you for the blog post.

    You should probably use a Spring Data Neo4j repository all along instead of your custom DAO implementation.

    Also for the readability of the blog post I would leave off the AJ config as well as the getters and setters of your objects.

    Perhaps you can update your example to Spring Data Neo4j 2.0.0.RELEASE which uses Neo4j 1.6.M02 and was released in December 2011.

    Thanks again

    Michael

    ResponderBorrar