添加到映射集时的NotInTransactionException

时间:2013-09-24 16:38:03

标签: spring neo4j spring-data spring-transactions spring-data-neo4j

我使用简单映射@NodeEntitiesPersonNode通过SDN映射了两个FamilyNodeFamilyNode有一个@RelatedTo集合,儿童。我还有一个FamilyService(使用Spring的@Service注释),@Transactional方法上有updateFamily注释。此方法加载给定id的FamilyNode,并使用回调接口来修改节点。在回调的一个实现中,我向子集合添加了PersonNode,这正在生成NotInTransactionException,特别是在Neo4J尝试创建{{1}之间的关系时}和FamilyNode

可以在github找到源代码,特别是failing test。以下是代码的相关部分:

FamilyNode.java:

PersonNode

PersonNode.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);
    }
}

FamilyRepository.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;
}

FamilyServiceImpl.java:

public interface FamilyRepository extends GraphRepository<Family> {
    public FamilyNode findById(String id);
}

和失败的测试,FamilyServiceTest.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;
    }

}

运行此测试会产生以下异常堆栈:

@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));
    }

}

我必须相信我在配置SDN或交易方面遗漏了一些东西,但却无法追踪它。

1 个答案:

答案 0 :(得分:2)

我最近在这里回答了这个问题: Spring Data Neo4J - NotInTransactionException while modifying set of nodeEntity

简而言之,它与这些List是由SDN支持的特殊列表这一事实有关,并且任何修改都会立即保存到DB。如果要防止此行为,则应在模型类中使用Iterable。如果您在阅读完链接后还有其他问题,请将其作为评论发布。