1

単純なマッピングを使用して SDN 経由で2 つ@NodeEntitiesをマッピングしPersonNodeましFamilyNodeた。コレクション、子FamilyNodeを持っています。メソッドに注釈付きの(Springの注釈を使用)@RelatedToもあります。このメソッドは、指定された ID をロードし、コールバック インターフェイスを使用してノードを変更します。コールバックの 1 つの実装では、子コレクションに を追加しています。これは、特に Neo4J が と の間の関係を作成しようとしている時点で、 を生成しています。FamilyService@Service@TransactionalupdateFamilyFamilyNodePersonNodeNotInTransactionExceptionFamilyNodePersonNode

ソース コードはgithubで見つけることができ、特に失敗したテストは. 関連するコードは次のとおりです。

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<>();
        for (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;
    }

}

失敗したテストである 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));
    }

}

このテストを実行すると、次の例外スタックが生成されます。

org.neo4j.graphdb.NotInTransactionException
    at org.neo4j.kernel.impl.core.NoTransactionState.acquireWriteLock(NoTransactionState.java:43)
    at org.neo4j.kernel.impl.transaction.LockType$2.acquire(LockType.java:51)
    at org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:473)
    at org.neo4j.kernel.InternalAbstractGraphDatabase$6.lookup(InternalAbstractGraphDatabase.java:733)
    at org.neo4j.kernel.impl.core.NodeProxy.createRelationshipTo(NodeProxy.java:207)
    at org.springframework.data.neo4j.fieldaccess.RelationshipHelper.obtainSingleRelationship(RelationshipHelper.java:62)
    at org.springframework.data.neo4j.fieldaccess.RelationshipHelper.createSingleRelationship(RelationshipHelper.java:142)
    at org.springframework.data.neo4j.fieldaccess.RelationshipHelper.createAddedRelationships(RelationshipHelper.java:96)
    at org.springframework.data.neo4j.fieldaccess.RelatedToFieldAccessor.createAddedRelationships(RelatedToFieldAccessor.java:78)
    at org.springframework.data.neo4j.fieldaccess.RelatedToCollectionFieldAccessorFactory$RelatedToCollectionFieldAccessor.setValue(RelatedToCollectionFieldAccessorFactory.java:68)
    at org.springframework.data.neo4j.fieldaccess.ManagedFieldAccessorSet.updateValue(ManagedFieldAccessorSet.java:112)
    at org.springframework.data.neo4j.fieldaccess.ManagedFieldAccessorSet.update(ManagedFieldAccessorSet.java:100)
    at org.springframework.data.neo4j.fieldaccess.ManagedFieldAccessorSet.add(ManagedFieldAccessorSet.java:126)
    at com.bonevich.ancestral.family.FamilyNode.addChild(FamilyNode.java:124)
    at com.bonevich.ancestral.family.FamilyServiceTest$1.update(FamilyServiceTest.java:64)
    at com.bonevich.ancestral.family.FamilyServiceImpl.updateFamily(FamilyServiceImpl.java:42)
    at com.bonevich.ancestral.family.FamilyServiceTest.testUpdateFamily(FamilyServiceTest.java:61)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

SDN またはトランザクションの構成で何かが欠けていると思わざるを得ませんが、それを突き止めることができませんでした。

4

1 に答える 1

2

私は最近、この質問にここで答えました: Spring Data Neo4J - NodeEntity のセットを変更しているときに NotInTransactionException

つまり、これらのリストは SDN に裏打ちされた特別なリストであり、変更はすぐに DB に永続化されるという事実に関係しています。この動作を防ぎたい場合は、モデル クラスで Iterable を使用する必要があります。リンクを読んだ後にさらに質問がある場合は、コメントとして投稿してください。

于 2013-09-25T12:35:18.287 に答える