我使用简单映射@NodeEntities
和PersonNode
通过SDN映射了两个FamilyNode
。 FamilyNode
有一个@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或交易方面遗漏了一些东西,但却无法追踪它。
答案 0 :(得分:2)
我最近在这里回答了这个问题: Spring Data Neo4J - NotInTransactionException while modifying set of nodeEntity
简而言之,它与这些List是由SDN支持的特殊列表这一事实有关,并且任何修改都会立即保存到DB。如果要防止此行为,则应在模型类中使用Iterable。如果您在阅读完链接后还有其他问题,请将其作为评论发布。