diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaCollectionFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaCollectionFieldAccessorFactory.java index fa7641261..bcf06d24c 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaCollectionFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaCollectionFieldAccessorFactory.java @@ -96,7 +96,7 @@ public class RelatedToViaCollectionFieldAccessorFactory implements FieldAccessor private void persistEntities( final Collection relationshipEntities, RelationshipType relationshipType ) { for (Object entity : relationshipEntities) { - template.save(entity, relationshipType); + template.save(entity, relationshipType, template.getMappingPolicy(entity)); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaSingleFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaSingleFieldAccessorFactory.java index bc3cc6dbc..2aa2995e5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaSingleFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelatedToViaSingleFieldAccessorFactory.java @@ -89,7 +89,7 @@ public class RelatedToViaSingleFieldAccessorFactory implements FieldAccessorFact private void persistEntities( final Collection relationshipEntities, RelationshipType relationshipType ) { for (Object entity : relationshipEntities) { - template.save(entity, relationshipType); + template.save(entity, relationshipType, template.getMappingPolicy(entity)); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/MappingPolicy.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/MappingPolicy.java index fafbce20b..e85a4795f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/MappingPolicy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/MappingPolicy.java @@ -27,9 +27,10 @@ import static java.util.Arrays.asList; public interface MappingPolicy { enum Option { - FIELD_DIRECT, SHOULD_LOAD,NO_TYPE_CHECK + FIELD_DIRECT, SHOULD_LOAD,NO_TYPE_CHECK, NO_RELOAD } boolean accessField(); + boolean noReload(); boolean shouldLoad(); boolean noTypeCheck(); MappingPolicy combineWith(MappingPolicy mappingPolicy); @@ -53,6 +54,11 @@ public interface MappingPolicy { return options.contains(Option.FIELD_DIRECT); } + @Override + public boolean noReload() { + return options.contains(Option.NO_RELOAD); + } + @Override public boolean shouldLoad() { return options.contains(Option.SHOULD_LOAD); @@ -111,6 +117,7 @@ public interface MappingPolicy { } public MappingPolicy LOAD_POLICY = new DefaultMappingPolicy(Option.SHOULD_LOAD); + public MappingPolicy NO_RELOAD_POLICY = new DefaultMappingPolicy(Option.NO_RELOAD); public MappingPolicy DEFAULT_POLICY = new DefaultMappingPolicy(); public MappingPolicy MAP_FIELD_DIRECT_POLICY = new DefaultMappingPolicy(Option.FIELD_DIRECT); public MappingPolicy NO_TYPE_CHECK_POLICY = new DefaultMappingPolicy(Option.NO_TYPE_CHECK); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java index fea891685..4e438587a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java @@ -91,6 +91,11 @@ public abstract class AbstractGraphRepository im return template.save(entity); } + @Transactional + public void saveOnly(U entity) { + template.saveOnly(entity); + } + @Override @Transactional public Iterable save(Iterable entities) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/CRUDRepository.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/CRUDRepository.java index 061ec5b92..c4f611ef2 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/CRUDRepository.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/CRUDRepository.java @@ -55,4 +55,6 @@ public interface CRUDRepository extends PagingAndSortingRepository { Result query(String query, Map params); + + void saveOnly(U entity); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java index 21f2be689..a6ca8098e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java @@ -351,13 +351,18 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware { @Override @SuppressWarnings("unchecked") public T save(T entity) { - return save(entity, null); + return save(entity, null, getMappingPolicy(entity)); + } + + @Override + public void saveOnly(T entity) { + save(entity, null, getMappingPolicy(entity).combineWith(MappingPolicy.NO_RELOAD_POLICY)); } @SuppressWarnings("unchecked") - public T save(T entity, final RelationshipType annotationProvidedRelationshipType) { + public T save(T entity, final RelationshipType annotationProvidedRelationshipType, MappingPolicy mappingPolicy) { if (applicationContext != null) applicationContext.publishEvent(new BeforeSaveEvent(this, entity)); - T t = (T) infrastructure.getEntityPersister().persist(entity, getMappingPolicy(entity), this, annotationProvidedRelationshipType); + T t = (T) infrastructure.getEntityPersister().persist(entity, mappingPolicy, this, annotationProvidedRelationshipType); if (applicationContext != null) applicationContext.publishEvent(new AfterSaveEvent(this, entity)); return t; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/mapping/Neo4jEntityPersister.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/mapping/Neo4jEntityPersister.java index 6b063135f..8ba49efdc 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/mapping/Neo4jEntityPersister.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/mapping/Neo4jEntityPersister.java @@ -245,12 +245,14 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert if (isNodeEntity(type)) { final Node node = this.getPersistentState(entity); this.nodeConverter.write(entity, node,mappingPolicy, template, null ); + if (mappingPolicy.noReload()) return null; return createEntityFromState(getPersistentState(entity),type, getMappingPolicy(type), template); //return entity; // TODO ? } if (isRelationshipEntity(type)) { final Relationship relationship = this.getPersistentState(entity); this.relationshipConverter.write(entity, relationship,mappingPolicy, template, annotationProvidedRelationshipType ); + if (mappingPolicy.noReload()) return null; return createEntityFromState(getPersistentState(entity),type, getMappingPolicy(type), template); // return entity; // TODO ? } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java index edf03c323..cc58f1746 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java @@ -261,6 +261,13 @@ public interface Neo4jOperations { */ T save(T entity); + /** + * Stores the given entity in the graph, if the entity is already attached to the graph, the node is updated, otherwise + * a new node is created. Attached relationships will be cascaded. + * This method is also provided by the appropriate repository. + */ + void saveOnly(T entity); + Number getId(Object entity); /** diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/EntityNeo4jTemplateTests.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/EntityNeo4jTemplateTests.java index 8ab832930..bba73aec9 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/EntityNeo4jTemplateTests.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/EntityNeo4jTemplateTests.java @@ -300,6 +300,16 @@ public class EntityNeo4jTemplateTests extends EntityTestBase { assertEquals("created node with name", "Thomas", node.getProperty("name")); } + @Test @Transactional + public void testSaveOnly() throws Exception { + final Person thomas = new Person("Thomas", 30); + neo4jOperations.saveOnly(thomas); + final Node node = getNodeState(thomas); + assertNotNull("created node",node); + assertEquals("created node with id", (Long) node.getId(), thomas.getId()); + assertEquals("created node with name", "Thomas", node.getProperty("name")); + } + static abstract class ManagedTestEntity implements ManagedEntity {} @Test @Transactional public void testIsManaged() throws Exception { diff --git a/src/main/asciidoc/reference/programming-model/template.adoc b/src/main/asciidoc/reference/programming-model/template.adoc index 8cd5fbec5..2a828ece8 100644 --- a/src/main/asciidoc/reference/programming-model/template.adoc +++ b/src/main/asciidoc/reference/programming-model/template.adoc @@ -50,7 +50,10 @@ Neo4jOperations neo = new Neo4jTemplate(graphDatabase); == Entity-Persistence -`Neo4jTemplate` allows to `save`, `find(One/All)`, `count`, `delete` and `projectTo` entities. It provides the stored type information via `getStoredJavaType` and can `fetch` lazy-loaded entities or `load` them altogether. +`Neo4jTemplate` allows to `save`,`saveOnly`, `find(One/All)`, `count`, `delete` and `projectTo` entities. It provides the stored type information via `getStoredJavaType` and can `fetch` lazy-loaded entities or `load` them altogether. + +The `saveOnly` method will not reload the entity from the database, saving a number of requests that are often not necessary. +It's also available in the `GraphRepository` interface. == Result @@ -86,7 +89,8 @@ Neo4j Template offers basic lifecycle events via Spring's event mechanism using * BeforeSaveEvent * AfterSaveEvent -* DeleteEvent - after the event has been deleted +* BeforeDeleteEvent +* AfterDeleteEvent The following example demonstrates how to hook into the application lifecycle and register listeners that perform behaviour across types of entities during this life cycle: @@ -121,10 +125,10 @@ public class ApplicationConfig extends Neo4jConfiguration { } @Bean - ApplicationListener deleteEventApplicationListener() { - return new ApplicationListener() { + ApplicationListener beforeDeleteEventApplicationListener() { + return new ApplicationListener() { @Override - public void onApplicationEvent(DeleteEvent event) { + public void onApplicationEvent(BeforeDeleteEvent event) { AcmeEntity entity = (AcmeEntity) event.getEntity(); auditLog.onEventDeleted(entity); }