DATAGRAPH-285 adding application events for save and delete
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.lifecycle;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class AfterSaveEvent<T> extends ApplicationEvent {
|
||||
private final T entity;
|
||||
|
||||
/**
|
||||
* Create a new ApplicationEvent.
|
||||
*
|
||||
* @param source the component that published the event (never <code>null</code>)
|
||||
* @param entity
|
||||
*/
|
||||
public AfterSaveEvent(Object source, T entity) {
|
||||
super(source);
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public T getEntity() {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.lifecycle;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class BeforeSaveEvent<T> extends ApplicationEvent {
|
||||
private final T entity;
|
||||
|
||||
/**
|
||||
* @param source the component that published the event (never <code>null</code>)
|
||||
* @param entity the entity that is about to be saved
|
||||
*/
|
||||
public BeforeSaveEvent(Object source, T entity) {
|
||||
super(source);
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public T getEntity() {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.lifecycle;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class DeleteEvent<T> extends ApplicationEvent {
|
||||
private final T entity;
|
||||
|
||||
public DeleteEvent(Object source, T entity) {
|
||||
super(source);
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public T getEntity() {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,9 @@ import org.neo4j.helpers.collection.ClosableIterable;
|
||||
import org.neo4j.index.lucene.ValueContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
@@ -36,6 +39,9 @@ import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.core.UncategorizedGraphStoreException;
|
||||
import org.springframework.data.neo4j.fieldaccess.GraphBackedEntityIterableWrapper;
|
||||
import org.springframework.data.neo4j.lifecycle.AfterSaveEvent;
|
||||
import org.springframework.data.neo4j.lifecycle.BeforeSaveEvent;
|
||||
import org.springframework.data.neo4j.lifecycle.DeleteEvent;
|
||||
import org.springframework.data.neo4j.mapping.IndexInfo;
|
||||
import org.springframework.data.neo4j.mapping.MappingPolicy;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
@@ -45,11 +51,7 @@ import org.springframework.data.neo4j.repository.NodeGraphRepositoryImpl;
|
||||
import org.springframework.data.neo4j.repository.RelationshipGraphRepository;
|
||||
import org.springframework.data.neo4j.support.index.IndexProvider;
|
||||
import org.springframework.data.neo4j.support.index.IndexType;
|
||||
import org.springframework.data.neo4j.support.mapping.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jPersistentEntityImpl;
|
||||
import org.springframework.data.neo4j.support.mapping.StoredEntityType;
|
||||
import org.springframework.data.neo4j.support.mapping.*;
|
||||
import org.springframework.data.neo4j.support.query.QueryEngine;
|
||||
import org.springframework.data.neo4j.template.GraphCallback;
|
||||
import org.springframework.data.neo4j.template.Neo4jOperations;
|
||||
@@ -78,10 +80,11 @@ import static org.springframework.data.neo4j.support.ParameterCheck.notNull;
|
||||
/*
|
||||
TODO This is a merge of GraphDatabaseContext and the previous Neo4jTemplate, so it still contains inconsistencies, if you spot them, please mark them with a TODO
|
||||
*/
|
||||
public class Neo4jTemplate implements Neo4jOperations {
|
||||
public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware {
|
||||
private static final Logger log = LoggerFactory.getLogger(Neo4jTemplate.class);
|
||||
|
||||
private final Infrastructure infrastructure;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* @param graphDatabase the neo4j graph database
|
||||
@@ -89,17 +92,17 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
*/
|
||||
public Neo4jTemplate(final GraphDatabase graphDatabase, PlatformTransactionManager transactionManager) {
|
||||
notNull(graphDatabase, "graphDatabase");
|
||||
this.infrastructure = MappingInfrastructureFactoryBean.createDirect(graphDatabase,transactionManager);
|
||||
this.infrastructure = MappingInfrastructureFactoryBean.createDirect(graphDatabase, transactionManager);
|
||||
}
|
||||
|
||||
public Neo4jTemplate(final GraphDatabase graphDatabase) {
|
||||
notNull(graphDatabase, "graphDatabase");
|
||||
this.infrastructure = MappingInfrastructureFactoryBean.createDirect(graphDatabase,null);
|
||||
this.infrastructure = MappingInfrastructureFactoryBean.createDirect(graphDatabase, null);
|
||||
}
|
||||
|
||||
public Neo4jTemplate(final GraphDatabaseService graphDatabaseService) {
|
||||
notNull(graphDatabaseService, "graphDatabaseService");
|
||||
this.infrastructure = MappingInfrastructureFactoryBean.createDirect(graphDatabaseService,null);
|
||||
this.infrastructure = MappingInfrastructureFactoryBean.createDirect(graphDatabaseService, null);
|
||||
}
|
||||
|
||||
public Neo4jTemplate(Infrastructure infrastructure) {
|
||||
@@ -109,7 +112,7 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
|
||||
@Override
|
||||
public <T> GraphRepository<T> repositoryFor(Class<T> clazz) {
|
||||
notNull(clazz,"entity type");
|
||||
notNull(clazz, "entity type");
|
||||
if (isNodeEntity(clazz)) return new NodeGraphRepositoryImpl<T>(clazz, this);
|
||||
if (isRelationshipEntity(clazz)) return new RelationshipGraphRepository<T>(clazz, this);
|
||||
throw new IllegalArgumentException("Can't create graph repository for non-graph entity of type " + clazz);
|
||||
@@ -143,12 +146,12 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(entityClass);
|
||||
if (persistentEntity.isNodeEntity()) {
|
||||
final Node node = getNode(id);
|
||||
if (node==null) return null;
|
||||
if (node == null) return null;
|
||||
return infrastructure.getEntityPersister().createEntityFromState(node, entityClass, persistentEntity.getMappingPolicy(), this);
|
||||
}
|
||||
if (persistentEntity.isRelationshipEntity()) {
|
||||
final Relationship relationship = getRelationship(id);
|
||||
if (relationship==null) return null;
|
||||
if (relationship == null) return null;
|
||||
return infrastructure.getEntityPersister().createEntityFromState(relationship, entityClass, persistentEntity.getMappingPolicy(), this);
|
||||
}
|
||||
throw new IllegalArgumentException("provided entity type is neither annotated with @NodeEntiy nor @RelationshipEntity");
|
||||
@@ -156,39 +159,41 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
|
||||
@Override
|
||||
public <T> EndResult<T> findAll(final Class<T> entityClass) {
|
||||
notNull(entityClass,"entity type");
|
||||
notNull(entityClass, "entity type");
|
||||
final ClosableIterable<PropertyContainer> all = infrastructure.getTypeRepresentationStrategies().findAll(getEntityType(entityClass));
|
||||
return new QueryResultBuilder<PropertyContainer>(all, getDefaultConverter()).to(entityClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long count(final Class<T> entityClass) {
|
||||
notNull(entityClass,"entity type");
|
||||
notNull(entityClass, "entity type");
|
||||
return infrastructure.getTypeRepresentationStrategies().count(getEntityType(entityClass));
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state, MappingPolicy mappingPolicy) {
|
||||
notNull(state,"node or relationship");
|
||||
notNull(state, "node or relationship");
|
||||
return infrastructure.getEntityPersister().createEntityFromStoredType(state, mappingPolicy, this);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type, MappingPolicy mappingPolicy) {
|
||||
notNull(state,"node or relationship");
|
||||
notNull(state, "node or relationship");
|
||||
return infrastructure.getEntityPersister().createEntityFromState(state, type, mappingPolicy, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends PropertyContainer, T> T load(S state, Class<T> type) {
|
||||
notNull(state,"node or relationship",type,"entity class");
|
||||
notNull(state, "node or relationship", type, "entity class");
|
||||
return infrastructure.getEntityPersister().createEntityFromState(state, type, getMappingPolicy(type), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T projectTo(Object entity, Class<T> targetType) {
|
||||
notNull(entity,"entity",targetType,"new entity class");
|
||||
notNull(entity, "entity", targetType, "new entity class");
|
||||
return infrastructure.getEntityPersister().projectTo(entity, targetType, this);
|
||||
}
|
||||
|
||||
public <T> T projectTo(Object entity, Class<T> targetType, MappingPolicy mappingPolicy) {
|
||||
notNull(entity,"entity",targetType,"new entity class");
|
||||
notNull(entity, "entity", targetType, "new entity class");
|
||||
return infrastructure.getEntityPersister().projectTo(entity, targetType, mappingPolicy, this);
|
||||
}
|
||||
|
||||
@@ -214,8 +219,9 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
|
||||
@Override
|
||||
public void delete(final Object entity) {
|
||||
notNull(entity, "entity");
|
||||
infrastructure.getEntityRemover().remove(entity);
|
||||
|
||||
if (applicationContext != null) applicationContext.publishEvent(new DeleteEvent<Object>(this, entity));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,12 +284,15 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T save(T entity) {
|
||||
return save( entity, null );
|
||||
return save(entity, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T save( T entity, RelationshipType annotationProvidedRelationshipType ) {
|
||||
return (T) infrastructure.getEntityPersister().persist(entity, getMappingPolicy(entity), this, annotationProvidedRelationshipType );
|
||||
public <T> T save(T entity, final RelationshipType annotationProvidedRelationshipType) {
|
||||
if (applicationContext != null) applicationContext.publishEvent(new BeforeSaveEvent<T>(this, entity));
|
||||
T t = (T) infrastructure.getEntityPersister().persist(entity, getMappingPolicy(entity), this, annotationProvidedRelationshipType);
|
||||
if (applicationContext != null) applicationContext.publishEvent(new AfterSaveEvent<T>(this, entity));
|
||||
return t;
|
||||
}
|
||||
|
||||
public boolean isManaged(Object entity) {
|
||||
@@ -311,10 +320,10 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R> R getRelationshipBetween(Object start, Object end, Class<R> relationshipEntityClass, String relationshipType) {
|
||||
notNull(start,"start",end,"end",relationshipEntityClass,"relationshipEntityClass",relationshipType,"relationshipType");
|
||||
notNull(start, "start", end, "end", relationshipEntityClass, "relationshipEntityClass", relationshipType, "relationshipType");
|
||||
final Relationship relationship = infrastructure.getEntityStateHandler().getRelationshipBetween(start, end, relationshipType);
|
||||
if (relationship == null) return null;
|
||||
if (Relationship.class.isAssignableFrom(relationshipEntityClass)) return (R)relationship;
|
||||
if (Relationship.class.isAssignableFrom(relationshipEntityClass)) return (R) relationship;
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(relationshipEntityClass);
|
||||
return infrastructure.getEntityPersister().createEntityFromState(relationship, relationshipEntityClass, persistentEntity.getMappingPolicy(), this);
|
||||
}
|
||||
@@ -322,27 +331,28 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R> Iterable<R> getRelationshipsBetween(Object start, Object end, Class<R> relationshipEntityClass, String relationshipType) {
|
||||
notNull(start,"start",end,"end",relationshipEntityClass,"relationshipEntityClass",relationshipType,"relationshipType");
|
||||
notNull(start, "start", end, "end", relationshipEntityClass, "relationshipEntityClass", relationshipType, "relationshipType");
|
||||
final Iterable<Relationship> relationships = infrastructure.getEntityStateHandler().getRelationshipsBetween(start, end, relationshipType);
|
||||
if (relationships == null) return null;
|
||||
if (Relationship.class.isAssignableFrom(relationshipEntityClass)) return (Iterable<R>)relationships;
|
||||
if (Relationship.class.isAssignableFrom(relationshipEntityClass)) return (Iterable<R>) relationships;
|
||||
return GraphBackedEntityIterableWrapper.create(relationships, relationshipEntityClass, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Relationship getRelationshipBetween(Object start, Object end, String relationshipType) {
|
||||
notNull(start,"start",end,"end",relationshipType,"relationshipType");
|
||||
notNull(start, "start", end, "end", relationshipType, "relationshipType");
|
||||
return infrastructure.getEntityStateHandler().getRelationshipBetween(start, end, relationshipType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRelationshipBetween(Object start, Object end, String type) {
|
||||
notNull(start,"start",end,"end",type,"relationshipType");
|
||||
notNull(start, "start", end, "end", type, "relationshipType");
|
||||
infrastructure.getEntityRemover().removeRelationshipBetween(start, end, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R createRelationshipBetween(Object start, Object end, Class<R> relationshipEntityClass, String relationshipType, boolean allowDuplicates) {
|
||||
notNull(start,"start",end,"end",relationshipEntityClass,"relationshipEntityClass",relationshipType,"relationshipType");
|
||||
notNull(start, "start", end, "end", relationshipEntityClass, "relationshipEntityClass", relationshipType, "relationshipType");
|
||||
final RelationshipResult result = infrastructure.getEntityStateHandler().createRelationshipBetween(start, end, relationshipType, allowDuplicates);
|
||||
if (result.type == RelationshipResult.Type.NEW) {
|
||||
// TODO
|
||||
@@ -364,7 +374,7 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
|
||||
@Override
|
||||
public Relationship getOrCreateRelationship(String indexName, String key, Object value, Node startNode, Node endNode, String type, Map<String, Object> properties) {
|
||||
return getGraphDatabase().getOrCreateRelationship(indexName,key,value,startNode,endNode,type,properties);
|
||||
return getGraphDatabase().getOrCreateRelationship(indexName, key, value, startNode, endNode, type, properties);
|
||||
}
|
||||
|
||||
private final Neo4jExceptionTranslator exceptionTranslator = new Neo4jExceptionTranslator();
|
||||
@@ -493,7 +503,7 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
public ResultConverter getDefaultConverter() {
|
||||
final ResultConverter resultConverter = infrastructure.getResultConverter();
|
||||
if (resultConverter instanceof Neo4jTemplateAware) {
|
||||
return ((Neo4jTemplateAware<ResultConverter>)resultConverter).with(this);
|
||||
return ((Neo4jTemplateAware<ResultConverter>) resultConverter).with(this);
|
||||
}
|
||||
return resultConverter;
|
||||
}
|
||||
@@ -507,7 +517,7 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Result<Map<String, Object>> query(String statement, Map<String, Object> params) {
|
||||
notNull(statement, "statement");
|
||||
final QueryEngine<Map<String,Object>> queryEngine = queryEngineFor(QueryType.Cypher);
|
||||
final QueryEngine<Map<String, Object>> queryEngine = queryEngineFor(QueryType.Cypher);
|
||||
return queryEngine.query(statement, params);
|
||||
}
|
||||
|
||||
@@ -526,7 +536,7 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Iterable<T> traverse(Object entity, Class<?> targetType, TraversalDescription traversalDescription) {
|
||||
notNull(entity,"entity",targetType,"target type",traversalDescription,"traversal description");
|
||||
notNull(entity, "entity", targetType, "target type", traversalDescription, "traversal description");
|
||||
return traverse(entity, traversalDescription).to((Class<T>) targetType);
|
||||
}
|
||||
|
||||
@@ -553,7 +563,7 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
|
||||
@Override
|
||||
public <T extends PropertyContainer> Result<T> lookup(final Class<?> indexedType, String propertyName, final Object value) {
|
||||
notNull(propertyName, "property name", indexedType, "indexedType",value,"query value");
|
||||
notNull(propertyName, "property name", indexedType, "indexedType", value, "query value");
|
||||
try {
|
||||
|
||||
final Index<T> index = getIndex(indexedType, propertyName);
|
||||
@@ -571,15 +581,15 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
@Override
|
||||
public <T extends PropertyContainer> Index<T> getIndex(Class<?> indexedType, String propertyName) {
|
||||
final Neo4jPersistentProperty property = getPersistentProperty(indexedType, propertyName);
|
||||
if (property==null) return getIndexProvider().getIndex(indexedType,null);
|
||||
if (property == null) return getIndexProvider().getIndex(indexedType, null);
|
||||
return getIndexProvider().getIndex(property, indexedType);
|
||||
}
|
||||
|
||||
public Neo4jPersistentProperty getPersistentProperty(Class<?> type, String propertyName) {
|
||||
if (type==null || propertyName==null) return null;
|
||||
if (type == null || propertyName == null) return null;
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(type);
|
||||
final int dotIndex = propertyName.lastIndexOf(".");
|
||||
if (dotIndex >-1) propertyName = propertyName.substring(dotIndex, propertyName.length());
|
||||
if (dotIndex > -1) propertyName = propertyName.substring(dotIndex, propertyName.length());
|
||||
return persistentEntity.getPersistentProperty(propertyName);
|
||||
}
|
||||
|
||||
@@ -635,27 +645,28 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
public String getIndexKey(Neo4jPersistentProperty property) {
|
||||
return property.getIndexKey();
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer> Index<S> getIndex(Neo4jPersistentProperty property, final Class<?> instanceType) {
|
||||
return getIndexProvider().getIndex(property, instanceType);
|
||||
}
|
||||
|
||||
|
||||
public MappingPolicy getMappingPolicy(Object entity) {
|
||||
ParameterCheck.notNull(entity,"entity");
|
||||
return getMappingPolicy( entity.getClass() );
|
||||
ParameterCheck.notNull(entity, "entity");
|
||||
return getMappingPolicy(entity.getClass());
|
||||
}
|
||||
|
||||
public StoredEntityType getStoredEntityType(Object entity) {
|
||||
final PropertyContainer container = entity instanceof PropertyContainer ? (PropertyContainer)entity: getPersistentState(entity);
|
||||
if (container==null) return null;
|
||||
final PropertyContainer container = entity instanceof PropertyContainer ? (PropertyContainer) entity : getPersistentState(entity);
|
||||
if (container == null) return null;
|
||||
final Object alias = getInfrastructure().getTypeRepresentationStrategies().readAliasFrom(container);
|
||||
return getMappingContext().getPersistentEntity(alias).getEntityType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getStoredJavaType(Object entity) {
|
||||
final PropertyContainer container = entity instanceof PropertyContainer ? (PropertyContainer)entity: getPersistentState(entity);
|
||||
if (container==null) return null;
|
||||
final PropertyContainer container = entity instanceof PropertyContainer ? (PropertyContainer) entity : getPersistentState(entity);
|
||||
if (container == null) return null;
|
||||
final Object alias = getInfrastructure().getTypeRepresentationStrategies().readAliasFrom(container);
|
||||
return getMappingContext().getPersistentEntity(alias).getType();
|
||||
}
|
||||
@@ -668,9 +679,14 @@ public class Neo4jTemplate implements Neo4jOperations {
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(entity.getClass());
|
||||
final Neo4jPersistentProperty uniqueProperty = persistentEntity.getUniqueProperty();
|
||||
Object value = uniqueProperty.getValueFromEntity(entity, MappingPolicy.MAP_FIELD_DIRECT_POLICY);
|
||||
if (value==null) return createNode();
|
||||
if (value == null) return createNode();
|
||||
final IndexInfo indexInfo = uniqueProperty.getIndexInfo();
|
||||
if (value instanceof Number && indexInfo.isNumeric()) value=ValueContext.numeric((Number)value);
|
||||
if (value instanceof Number && indexInfo.isNumeric()) value = ValueContext.numeric((Number) value);
|
||||
return getGraphDatabase().getOrCreateNode(indexInfo.getIndexName(), indexInfo.getIndexKey(), value, Collections.<String, Object>emptyMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.lifecycle;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.neo4j.helpers.collection.IteratorUtil.single;
|
||||
|
||||
@NodeEntity
|
||||
class Bar {
|
||||
@GraphId
|
||||
Long id;
|
||||
|
||||
String generatedId = "no event";
|
||||
}
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class AfterSaveEventTests {
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories
|
||||
static class TestConfig extends Neo4jConfiguration {
|
||||
@Bean
|
||||
GraphDatabaseService graphDatabaseService() {
|
||||
return new ImpermanentGraphDatabase();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ApplicationListener<AfterSaveEvent> beforeSaveEventApplicationListener() {
|
||||
return new ApplicationListener<AfterSaveEvent>() {
|
||||
@Override
|
||||
public void onApplicationEvent(AfterSaveEvent event) {
|
||||
Bar bar = (Bar) event.getEntity();
|
||||
bar.generatedId = "after event";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private Neo4jTemplate template;
|
||||
|
||||
@Test
|
||||
public void shouldFireAfterEntityIsSaved() throws Exception {
|
||||
Bar entity = new Bar();
|
||||
assertThat(template.save(entity).generatedId, is("no event"));
|
||||
assertThat(entity.generatedId, is("after event"));
|
||||
assertThat(single(template.findAll(Bar.class)).generatedId, is("no event"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.lifecycle;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.neo4j.helpers.collection.IteratorUtil.single;
|
||||
|
||||
@NodeEntity
|
||||
class Foo {
|
||||
@GraphId
|
||||
Long id;
|
||||
|
||||
String generatedId = "no event";
|
||||
}
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class BeforeSaveEventTests {
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories
|
||||
static class TestConfig extends Neo4jConfiguration {
|
||||
@Bean
|
||||
GraphDatabaseService graphDatabaseService() {
|
||||
return new ImpermanentGraphDatabase();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ApplicationListener<BeforeSaveEvent> beforeSaveEventApplicationListener() {
|
||||
return new ApplicationListener<BeforeSaveEvent>() {
|
||||
@Override
|
||||
public void onApplicationEvent(BeforeSaveEvent event) {
|
||||
Foo foo = (Foo) event.getEntity();
|
||||
foo.generatedId = "before event";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private Neo4jTemplate template;
|
||||
|
||||
@Test
|
||||
public void shouldFireBeforeEntityIsSaved() throws Exception {
|
||||
assertThat(template.save(new Foo()).generatedId, is("before event"));
|
||||
assertThat(single(template.findAll(Foo.class)).generatedId, is("before event"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.lifecycle;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.node.Neo4jHelper;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.transaction.BeforeTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.matchers.JUnitMatchers.hasItem;
|
||||
|
||||
@NodeEntity
|
||||
class Program {
|
||||
@GraphId
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
Program() {
|
||||
}
|
||||
|
||||
public Program(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class DeleteEventTests {
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories
|
||||
static class TestConfig extends Neo4jConfiguration {
|
||||
@Bean
|
||||
GraphDatabaseService graphDatabaseService() {
|
||||
return new ImpermanentGraphDatabase();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ApplicationListener<DeleteEvent<Program>> deleteEventApplicationListener() {
|
||||
return new ApplicationListener<DeleteEvent<Program>>() {
|
||||
@Override
|
||||
public void onApplicationEvent(DeleteEvent<Program> event) {
|
||||
deletions.add(event.getEntity());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
Neo4jTemplate template;
|
||||
|
||||
@Autowired
|
||||
GraphDatabaseService graphDatabaseService;
|
||||
|
||||
static final LinkedList<Program> deletions = new LinkedList<Program>();
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
Neo4jHelper.cleanDb(template);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
deletions.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventOnNodeDeletion() throws Exception {
|
||||
Program sark = template.save(new Program("Sark"));
|
||||
|
||||
template.delete(sark);
|
||||
|
||||
assertThat(deletions, hasItem(sark));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.lifecycle;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.annotation.*;
|
||||
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.node.Neo4jHelper;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.transaction.BeforeTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.matchers.JUnitMatchers.either;
|
||||
import static org.springframework.data.neo4j.SetHelper.asSet;
|
||||
|
||||
@RelationshipEntity(type = "slew")
|
||||
class Slaying {
|
||||
@GraphId
|
||||
Long id;
|
||||
|
||||
@StartNode
|
||||
FictionalCharacter slayor;
|
||||
|
||||
@EndNode
|
||||
FictionalCharacter slayee;
|
||||
|
||||
String battle;
|
||||
|
||||
Slaying() {
|
||||
}
|
||||
|
||||
Slaying(FictionalCharacter slayor, FictionalCharacter slayee, String battle) {
|
||||
this.slayor = slayor;
|
||||
this.slayee = slayee;
|
||||
this.battle = battle;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NodeEntity
|
||||
class FictionalCharacter {
|
||||
@GraphId
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@RelatedToVia
|
||||
Slaying slew;
|
||||
|
||||
@RelatedToVia(type = "slayered")
|
||||
Set<Slaying> slayings;
|
||||
|
||||
FictionalCharacter() {
|
||||
}
|
||||
|
||||
FictionalCharacter(String name) {
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
void slew(FictionalCharacter fictionalCharacter, String battle) {
|
||||
slew = new Slaying(this, fictionalCharacter, battle);
|
||||
}
|
||||
|
||||
void slew(FictionalCharacter... victims) {
|
||||
slayings = new HashSet<Slaying>();
|
||||
|
||||
for (FictionalCharacter victim : victims) {
|
||||
slayings.add(new Slaying(this, victim, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NodeEntity
|
||||
class Parent {
|
||||
@GraphId
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@Fetch
|
||||
Child eldest;
|
||||
|
||||
@Fetch
|
||||
Set<Child> youngsters;
|
||||
|
||||
Parent() {
|
||||
|
||||
}
|
||||
|
||||
Parent(Child eldest) {
|
||||
this.eldest = eldest;
|
||||
}
|
||||
|
||||
public Parent(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Parent(Set<Child> youngsters) {
|
||||
this.youngsters = youngsters;
|
||||
}
|
||||
}
|
||||
|
||||
@NodeEntity
|
||||
class Child {
|
||||
@GraphId
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
Child() {
|
||||
}
|
||||
|
||||
Child(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Child child = (Child) o;
|
||||
|
||||
if (id != null ? !id.equals(child.id) : child.id != null) return false;
|
||||
if (name != null ? !name.equals(child.name) : child.name != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id != null ? id.hashCode() : 0;
|
||||
result = 31 * result + (name != null ? name.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class SaveEventTests {
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories
|
||||
static class TestConfig extends Neo4jConfiguration {
|
||||
@Bean
|
||||
GraphDatabaseService graphDatabaseService() {
|
||||
return new ImpermanentGraphDatabase();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ApplicationListener<BeforeSaveEvent> beforeSaveEventApplicationListener() {
|
||||
return new ApplicationListener<BeforeSaveEvent>() {
|
||||
@Override
|
||||
public void onApplicationEvent(BeforeSaveEvent event) {
|
||||
entities.add(event.getEntity());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
Neo4jTemplate template;
|
||||
|
||||
static final LinkedList<Object> entities = new LinkedList<Object>();
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
Neo4jHelper.cleanDb(template);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
entities.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventForNodeEntity() throws Exception {
|
||||
Child child = new Child();
|
||||
template.save(child);
|
||||
|
||||
assertThat(entities.size(), is(1));
|
||||
assertThat((Child) entities.get(0), is(child));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventForRelationshipEntity() throws Exception {
|
||||
FictionalCharacter fingolfin = template.save(new FictionalCharacter("Fingolfin"));
|
||||
FictionalCharacter morgoth = template.save(new FictionalCharacter("Morgoth"));
|
||||
entities.clear();
|
||||
Slaying slaying = new Slaying(morgoth, fingolfin, "Dagor Bragollach");
|
||||
|
||||
template.save(slaying);
|
||||
|
||||
assertThat(entities.size(), is(1));
|
||||
assertThat(((Slaying) entities.get(0)).battle, is(equalTo("Dagor Bragollach")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventForNodeEntities() throws Exception {
|
||||
Child child1 = new Child("Huey");
|
||||
Child child2 = new Child("Louie");
|
||||
Child child3 = new Child("Dewey");
|
||||
Parent parent = new Parent(asSet(child1, child2, child3));
|
||||
template.save(parent);
|
||||
|
||||
assertThat(entities.size(), is(4));
|
||||
assertThat((Parent) entities.get(0), is(parent));
|
||||
assertThat((Child) entities.get(1), is(child1));
|
||||
assertThat((Child) entities.get(2), is(child2));
|
||||
assertThat((Child) entities.get(3), is(child3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventForRelationshipEntities() throws Exception {
|
||||
FictionalCharacter beleg = template.save(new FictionalCharacter("Beleg"));
|
||||
FictionalCharacter brandir = template.save(new FictionalCharacter("Brandir"));
|
||||
entities.clear();
|
||||
FictionalCharacter turin = new FictionalCharacter("Túrin");
|
||||
turin.slew(beleg, brandir);
|
||||
|
||||
template.save(turin);
|
||||
|
||||
assertThat(entities.size(), is(3));
|
||||
assertThat(((FictionalCharacter) entities.get(0)).id, is(turin.id));
|
||||
assertThat(((Slaying) entities.get(1)).slayee.id, is(either(equalTo(beleg.id)).or(equalTo(brandir.id))));
|
||||
assertThat(((Slaying) entities.get(2)).slayee.id, is(either(equalTo(beleg.id)).or(equalTo(brandir.id))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventForNodeEntityWhenItIsSavedIndirectly() throws Exception {
|
||||
Child child = new Child();
|
||||
Parent parent = new Parent(child);
|
||||
template.save(parent);
|
||||
|
||||
assertThat(entities.size(), is(2));
|
||||
assertThat((Parent) entities.get(0), is(parent));
|
||||
assertThat((Child) entities.get(1), is(child));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventForRelationshipEntityWhenItIsSavedIndirectly() throws Exception {
|
||||
FictionalCharacter fingolfin = template.save(new FictionalCharacter("Fingolfin"));
|
||||
entities.clear();
|
||||
FictionalCharacter morgoth = new FictionalCharacter("Morgoth");
|
||||
morgoth.slew(fingolfin, "Dagor Bragollach");
|
||||
|
||||
template.save(morgoth);
|
||||
|
||||
assertThat(entities.size(), is(2));
|
||||
assertThat(((FictionalCharacter) entities.get(0)).id, is(morgoth.id));
|
||||
assertThat(((Slaying) entities.get(1)).battle, is(equalTo("Dagor Bragollach")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventForUpdatedEntities() throws Exception {
|
||||
Parent parent = template.save(new Parent("Donald Duck"));
|
||||
entities.clear();
|
||||
parent = template.findOne(parent.id, Parent.class);
|
||||
parent.name = "Mickey Mouse";
|
||||
|
||||
template.save(parent);
|
||||
|
||||
assertThat(entities.size(), is(1));
|
||||
assertThat((Parent) entities.get(0), is(parent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFireEventEvenIfEntityHasNotBeenUpdated() throws Exception {
|
||||
Parent parent = template.save(new Parent("Uncle Scrooge"));
|
||||
entities.clear();
|
||||
parent = template.findOne(parent.id, Parent.class);
|
||||
|
||||
template.save(parent);
|
||||
|
||||
assertThat(entities.size(), is(1));
|
||||
assertThat((Parent) entities.get(0), is(parent));
|
||||
}
|
||||
|
||||
/**
|
||||
* because we do not save recursively, the child entity isn't saved and thus no event is fired
|
||||
* <p/>
|
||||
* so this is basically saying, "we do not save recursively"
|
||||
* <p/>
|
||||
* is that different in the advanced mapping mode case?
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotFireEventForUpdatedRelatedEntities() throws Exception {
|
||||
Parent parent = template.save(new Parent(new Child("Daisy Duck")));
|
||||
entities.clear();
|
||||
parent = template.findOne(parent.id, Parent.class);
|
||||
parent.eldest.name = "Minnie Mouse";
|
||||
|
||||
template.save(parent);
|
||||
|
||||
assertThat(entities.size(), is(1));
|
||||
assertThat((Parent) entities.get(0), is(parent));
|
||||
}
|
||||
}
|
||||
@@ -107,4 +107,35 @@
|
||||
via the graph database.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Lifecycle Events</title>
|
||||
<para>Neo4j Template offers basic lifecycle events via Spring's event mechanism using ApplicationListener and ApplicationEvent. The following hooks are available in the form of types of application event:</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>BeforeSaveEvent</para></listitem>
|
||||
<listitem><para>AfterSaveEvent</para></listitem>
|
||||
<listitem><para>DeleteEvent - after the event has been deleted</para></listitem>
|
||||
</itemizedlist>
|
||||
<para>The following example demostrates how to register a listener and perform behaviour across types of entities</para>
|
||||
<example>
|
||||
<title>Timestamping Entities</title>
|
||||
<programlisting language="java">
|
||||
<![CDATA[@Configuration
|
||||
@EnableNeo4jRepositories
|
||||
public class ApplicationConfig extends Neo4jConfiguration {
|
||||
...
|
||||
@Bean
|
||||
ApplicationListener<BeforeSaveEvent> beforeSaveEventApplicationListener() {
|
||||
return new ApplicationListener<BeforeSaveEvent>() {
|
||||
@Override
|
||||
public void onApplicationEvent(BeforeSaveEvent event) {
|
||||
Auditable entity = (Auditable) event.getEntity();
|
||||
entity.setLastUpdated(new Date());
|
||||
}
|
||||
};
|
||||
}
|
||||
...]]>
|
||||
</programlisting>
|
||||
</example>
|
||||
<para>Changes made to entities in the before-save event handler are reflected in the stored entity - after-save ones are not.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user