我正在尝试从嵌入式图表中删除节点。
我正在使用SDN 3.3.2.RELEASE而我的Neo4j是2.2.4。
但是在存储库调用之后,节点仍然存在:
org.junit.ComparisonFailure: expected:<null> but was:<Manufacturer [name=Siemens]>
这是我的测试:
@Test
public void testDeleteById() {
Neo4JManufacturer loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).exists();
neo4JManufacturerRepository.deleteManufacturer(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).doesNotExist();
}
存储库是:
public interface Neo4JManufacturerRepository extends GraphRepository<Neo4JManufacturer> {
@Transactional
@Query("start u = node({id}) match u-[r]-() delete u,r")
public void deleteManufacturer(@Param("id") Long id);
在尝试使用deleteManufacturer()方法删除之前,我尝试使用delete()方法删除,如:
neo4JManufacturerRepository.delete(manufacturer0.getId());
但我会得到完全相同的测试失败:
org.junit.ComparisonFailure: expected:<null> but was:<Manufacturer [name=Siemens]>
这是我的节点类:
@NodeEntity
@SequenceGenerator(name = "id_generator", sequenceName = "sq_id_manufacturer")
public class Neo4JManufacturer extends BaseEntity {
@Column(nullable = false, unique = true)
@Indexed
private String name;
public Neo4JManufacturer() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Manufacturer [name=" + name + "]";
}
}
更新:
在这两条评论之后,我在删除调用之后添加了另一个find调用,以便触发对数据存储的刷新:
Neo4JManufacturer loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).exists();
neo4JManufacturerRepository.delete(manufacturer0.getId());
loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).doesNotExist();
我还在查询中添加了可选子句:
@Transactional
@Query("START u = node({id}) OPTIONAL MATCH u-[r]-() DELETE u,r")
public void deleteManufacturer(@Param("id") Long id);
现在,我得到了一个不同的错误:
No primary SDN label exists .. (i.e one starting with _)
我想在尝试删除后刷新,但是由于其他原因而失败了?
另外,我想知道在使用JPA和使用Neo4j时,冲洗和transactin行为是否相同。实际上,以下JPA测试的工作方式与预期一致:
@Test
public void testDeleteByUserId() {
User loadedUser = userRepository.findOne(user0.getId());
assertThatUser(loadedUser).exists();
loadedUser = userRepository.deleteByUserId(user0.getId());
loadedUser = userRepository.findOne(user0.getId());
assertThatUser(loadedUser).doesNotExist();
}
我的想法是对Neo4j数据库做同样的事情。
更新:我现在正在删除事务服务而不是直接在存储库上删除:
@Modifying
@Transactional(rollbackFor = EntityNotFoundException.class)
@Override
public Neo4JManufacturer delete(Long id) throws EntityNotFoundException {
Neo4JManufacturer manufacturer = findById(id);
if (manufacturer == null) {
throw new EntityNotFoundException();
} else {
neo4jManufacturerRepository.delete(manufacturer.getId());
return manufacturer;
}
}
该服务被称为:
@Test
public void testDeleteById() {
Neo4JManufacturer loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).exists();
neo4JManufacturerService.delete(manufacturer0.getId());
Neo4JManufacturer anotherManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(anotherManufacturer).doesNotExist();
}
但我仍然得到同样的例外:
testDeleteById(it.kahoot.robot.data.neo4j.Neo4JManufacturerRepositoryTest) Time elapsed: 0.137 sec <<< ERROR!
org.springframework.dao.InvalidDataAccessApiUsageException: No primary SDN label exists .. (i.e one starting with _) ; nested exception is java.lang.IllegalStateException: No primary SDN label exists .. (i.e one starting with _)
at org.springframework.data.neo4j.support.typerepresentation.LabelBasedNodeTypeRepresentationStrategy.readAliasFrom(LabelBasedNodeTypeRepresentationStrategy.java:136)
at org.springframework.data.neo4j.support.typerepresentation.LabelBasedNodeTypeRepresentationStrategy.readAliasFrom(LabelBasedNodeTypeRepresentationStrategy.java:40)
at org.springframework.data.neo4j.support.mapping.TRSTypeAliasAccessor.readAliasFrom(TRSTypeAliasAccessor.java:36)
at org.springframework.data.neo4j.support.mapping.TRSTypeAliasAccessor.readAliasFrom(TRSTypeAliasAccessor.java:26)
at org.springframework.data.convert.DefaultTypeMapper.readType(DefaultTypeMapper.java:102)
更新II:我现在有一个测试通过罚款并按预期运行。测试仍在@Transactional注释下进行。并且它不会进行任何手动冲洗。有趣的部分,以及测试停止给出错误的原因:
No primary SDN label exists .. (i.e one starting with _)
是findById或findOne调用被findByName调用替换。执行findById或findOne调用会触发上述错误。
以下是工作测试的结果:
@Test
public void testIsDelete() {
Neo4JManufacturer loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).exists();
neo4JManufacturerRepository.delete(manufacturer0.getId());
loadedManufacturer = neo4JManufacturerService.findByName(loadedManufacturer.getName());
assertThatManufacturer(loadedManufacturer).doesNotExist();
}
存储库findByName是:
Neo4JManufacturer findByName(String name);
我有一个记录器,显示id设置在0以上
DEBUG [Neo4JManufacturerRepositoryTest] ==========>> Id: 4 Name: Siemens
但是,使用findById而不是findByName会产生上述错误。
我想知道为什么。
更新III:
我现在已经从测试中删除了事务注释。
以下是测试:
@Test
public void testDelete() {
Neo4JManufacturer loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).exists();
neo4JManufacturerRepository.delete(manufacturer0.getId());
loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).doesNotExist();
assertThatManufacturer(manufacturer0).exists();
manufacturer0 = neo4JManufacturerRepository.save(manufacturer0);
}
控制台说:
2016-09-01 14:45:57,769 DEBUG [main] c.t.d.n.Neo4JManufacturerRepositoryTest ==========>> Before - Created manufacturer0 - Id: 0
2016-09-01 14:45:58,127 DEBUG [main] c.t.d.n.Neo4JManufacturerRepositoryTest ==========>> After - Deleted manufacturer0 - Id: 0
2016-09-01 14:45:58,320 DEBUG [main] c.t.d.n.Neo4JManufacturerRepositoryTest ==========>> Before - Created manufacturer0 - Id: 4
2016-09-01 14:45:58,850 DEBUG [main] c.t.d.n.Neo4JManufacturerRepositoryTest ==========>> After - Deleted manufacturer0 - Id: 4
2016-09-01 14:45:59,035 DEBUG [main] c.t.d.n.Neo4JManufacturerRepositoryTest ==========>> Before - Created manufacturer0 - Id: 8
Tests run: 4, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 23.625 sec <<< FAILURE! - in com.thalasoft.data.neo4j.Neo4JManufacturerRepositoryTest
testDelete(com.thalasoft.data.neo4j.Neo4JManufacturerRepositoryTest) Time elapsed: 0.334 sec <<< ERROR!
org.springframework.dao.DataRetrievalFailureException: Node 8 not found; nested exception is org.neo4j.graphdb.NotFoundException: Node 8 not found
它在测试的最后一个源代码行上出错,即执行save()操作的那个。
为什么要查找节点?为什么抱怨没找到?不应该找不到,因为我正在尝试创建它?
答案 0 :(得分:2)
由于您的Cypher查询正在使用MATCH u-[r]-()
,如果指定的节点没有参与任何关系,它将失败。
您应该使用OPTIONAL MATCH
,即使指定的节点没有参与任何关系,也可以使查询成功:
"START u = node({id}) OPTIONAL MATCH u-[r]-() DELETE u,r"
答案 1 :(得分:1)
在同一事务中,节点仍然可见,并且由于您的测试很可能是每个方法的@Transactional,因此tx仅在方法完成后完成(回滚)
请参阅:http://neo4j.com/docs/stable/transactions-delete.html
如果在删除后添加事务处理(提交)而没有在测试之上使用@Transactional。你不应该再看到节点了。
我按照我的解释进行了测试。
您的测试(通过其超类)具有@Transactional注释,因此测试方法中的所有操作都在一个事务中执行,然后回滚。
如果您想要查看真实世界的行为,则在该事务完成后,删除必须在其自身的tx中发生(作为服务调用的一部分),该节点将不再可见。
此外,您的断言测试了先前加载的节点将为空,这绝不是这种情况,因为现有变量未作为删除操作的一部分进行更改。
我从test-superclass中删除了全局@Transactional注释,并将测试方法更改为:
@Test
public void testDeleteById() {
Neo4JManufacturer loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).exists();
neo4JManufacturerService.delete(manufacturer0.getId());
loadedManufacturer = neo4JManufacturerRepository.findOne(manufacturer0.getId());
// both would work
// loadedManufacturer = neo4JManufacturerService.findById(manufacturer0.getId());
assertThatManufacturer(loadedManufacturer).doesNotExist();
}
现在它传递并展示了预期的行为:在完成删除的tx之后,节点就消失了。