spring - NotInTransactionException when adding to mapped set -
i have 2 @nodeentities
mapped via sdn using simple mapping, personnode
, familynode
. familynode
has @relatedto
collection, children. have familyservice
(using spring's @service
annotation) @transactional
annotation on updatefamily
method. method loads familynode
given id, , uses callback interface modify node. in 1 implementation of callback, adding personnode
children collection, , generating notintransactionexception
, @ point neo4j attempting create relationship between familynode
, personnode
.
source code can found @ github , in particular failing test. here relevant bits of code:
familynode.java:
@nodeentity public class familynode implements family { @indexed(indexname = "families", unique = true) private string id; @graphid private long identifier; @relatedto(elementclass = personnode.class, type = "child") private set<person> children; void addchild(person child) { if (this.children == null) { this.children = new hashset<>(); } this.children.add(child); } }
personnode.java:
@nodeentity public class personnode implements person { @relatedto(elementclass = familynode.class, type = "child", direction = incoming) private family childof; @indexed(indexname = "people", unique = true) private string id; @graphid private long identifier; }
familyrepository.java:
public interface familyrepository extends graphrepository<family> { public familynode findbyid(string id); }
familyserviceimpl.java:
@service public class familyserviceimpl implements familyservice { @autowired private familyrepository families; @autowired private neo4jtemplate template; @override public list<family> getfamilies(string[] ids) { list<family> families = new arraylist<>(); (string id : ids) { families.add(getfamily(id)); } return families; } @override public family getfamily(string id) { return familynode(id); } @override @transactional public family createfamily(family family) { return lazyloadrelationships((familynode) this.families.save(family)); } @override @transactional public family updatefamily(string id, familynodeupdater updater) { return this.families.save(updater.update(familynode(id))); } private familynode familynode(string id) { return lazyloadrelationships(this.families.findbyid(id)); } private familynode lazyloadrelationships(familynode family) { this.template.fetch(family.getfather()); this.template.fetch(family.getmother()); this.template.fetch(family.getchildren()); return family; } }
and failing test, familyservicetest.java:
@runwith(springjunit4classrunner.class) @contextconfiguration(loader = annotationconfigcontextloader.class, classes = { testconfig.class }) public class familyservicetest { @configuration @componentscan(basepackageclasses = { com.bonevich.ancestral.family.familyserviceimpl.class }, resourcepattern = "familyserviceimpl.class") @enableneo4jrepositories(basepackageclasses = { com.bonevich.ancestral.family.familynode.class }) static class testconfig extends neo4jconfiguration { @bean public graphdatabaseservice graphdatabaseservice() { return new graphdatabasefactory().newembeddeddatabasebuilder("/data/neo4j/ancestral-familyservicetest/") .newgraphdatabase(); } } @autowired private familyservice families; @autowired private graphdatabaseservice graphdatabaseservice; @autowired private neo4jtemplate neo4jtemplate; @test public void testupdatefamily() { this.families.createfamily(familynode.instance("testfamily")); transaction tx = this.graphdatabaseservice.begintx(); personnode person = personnode.instance("john", "johanson", "m", "a_person"); personnode expectedchild = this.neo4jtemplate.save(person); final long childid = expectedchild.getidentifier(); tx.success(); tx.finish(); family actualfamily = this.families.updatefamily("testfamily", new familynodeupdater() { @override public familynode update(familynode family) { family.addchild(familyservicetest.this.neo4jtemplate.findone(childid, personnode.class)); return family; } }); assertthat(actualfamily.getid(), is("testfamily")); assertthat(actualfamily.getchildren().get(0), is((person) expectedchild)); } }
running test yields following exception stack:
org.neo4j.graphdb.notintransactionexception @ org.neo4j.kernel.impl.core.notransactionstate.acquirewritelock(notransactionstate.java:43) @ org.neo4j.kernel.impl.transaction.locktype$2.acquire(locktype.java:51) @ org.neo4j.kernel.impl.core.nodemanager.getnodeforproxy(nodemanager.java:473) @ org.neo4j.kernel.internalabstractgraphdatabase$6.lookup(internalabstractgraphdatabase.java:733) @ org.neo4j.kernel.impl.core.nodeproxy.createrelationshipto(nodeproxy.java:207) @ org.springframework.data.neo4j.fieldaccess.relationshiphelper.obtainsinglerelationship(relationshiphelper.java:62) @ org.springframework.data.neo4j.fieldaccess.relationshiphelper.createsinglerelationship(relationshiphelper.java:142) @ org.springframework.data.neo4j.fieldaccess.relationshiphelper.createaddedrelationships(relationshiphelper.java:96) @ org.springframework.data.neo4j.fieldaccess.relatedtofieldaccessor.createaddedrelationships(relatedtofieldaccessor.java:78) @ org.springframework.data.neo4j.fieldaccess.relatedtocollectionfieldaccessorfactory$relatedtocollectionfieldaccessor.setvalue(relatedtocollectionfieldaccessorfactory.java:68) @ org.springframework.data.neo4j.fieldaccess.managedfieldaccessorset.updatevalue(managedfieldaccessorset.java:112) @ org.springframework.data.neo4j.fieldaccess.managedfieldaccessorset.update(managedfieldaccessorset.java:100) @ org.springframework.data.neo4j.fieldaccess.managedfieldaccessorset.add(managedfieldaccessorset.java:126) @ com.bonevich.ancestral.family.familynode.addchild(familynode.java:124) @ com.bonevich.ancestral.family.familyservicetest$1.update(familyservicetest.java:64) @ com.bonevich.ancestral.family.familyserviceimpl.updatefamily(familyserviceimpl.java:42) @ com.bonevich.ancestral.family.familyservicetest.testupdatefamily(familyservicetest.java:61) @ sun.reflect.nativemethodaccessorimpl.invoke0(native method) @ sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:57) @ sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:43) @ java.lang.reflect.method.invoke(method.java:606) @ org.junit.runners.model.frameworkmethod$1.runreflectivecall(frameworkmethod.java:47) @ org.junit.internal.runners.model.reflectivecallable.run(reflectivecallable.java:12) @ org.junit.runners.model.frameworkmethod.invokeexplosively(frameworkmethod.java:44) @ org.junit.internal.runners.statements.invokemethod.evaluate(invokemethod.java:17) @ org.springframework.test.context.junit4.statements.runbeforetestmethodcallbacks.evaluate(runbeforetestmethodcallbacks.java:74) @ org.springframework.test.context.junit4.statements.runaftertestmethodcallbacks.evaluate(runaftertestmethodcallbacks.java:83) @ org.springframework.test.context.junit4.statements.springrepeat.evaluate(springrepeat.java:72) @ org.springframework.test.context.junit4.springjunit4classrunner.runchild(springjunit4classrunner.java:231) @ org.springframework.test.context.junit4.springjunit4classrunner.runchild(springjunit4classrunner.java:88) @ org.junit.runners.parentrunner$3.run(parentrunner.java:238) @ org.junit.runners.parentrunner$1.schedule(parentrunner.java:63) @ org.junit.runners.parentrunner.runchildren(parentrunner.java:236) @ org.junit.runners.parentrunner.access$000(parentrunner.java:53) @ org.junit.runners.parentrunner$2.evaluate(parentrunner.java:229) @ org.springframework.test.context.junit4.statements.runbeforetestclasscallbacks.evaluate(runbeforetestclasscallbacks.java:61) @ org.springframework.test.context.junit4.statements.runaftertestclasscallbacks.evaluate(runaftertestclasscallbacks.java:71) @ org.junit.runners.parentrunner.run(parentrunner.java:309) @ org.springframework.test.context.junit4.springjunit4classrunner.run(springjunit4classrunner.java:174) @ org.eclipse.jdt.internal.junit4.runner.junit4testreference.run(junit4testreference.java:50) @ org.eclipse.jdt.internal.junit.runner.testexecution.run(testexecution.java:38) @ org.eclipse.jdt.internal.junit.runner.remotetestrunner.runtests(remotetestrunner.java:467) @ org.eclipse.jdt.internal.junit.runner.remotetestrunner.runtests(remotetestrunner.java:683) @ org.eclipse.jdt.internal.junit.runner.remotetestrunner.run(remotetestrunner.java:390) @ org.eclipse.jdt.internal.junit.runner.remotetestrunner.main(remotetestrunner.java:197)
i have got believe missing in configuring sdn or transactions, have been unable track down.
i answered question here: spring data neo4j - notintransactionexception while modifying set of nodeentity
in short, has fact these list special list backed sdn , modification persisted db. if want prevent behaviour, should use iterable in model classes. if have more question after reading link, post them comment.
Comments
Post a Comment