从 Spring 应用程序中删除 Neo4j 节点

Deleting a Neo4j node from a Spring application

我正在尝试从嵌入图中删除节点。

我使用的是 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]>

这是我的节点class:

@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 + "]";
  }

}

更新:

根据这两条评论,我在 delete 调用之后添加了另一个 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 时刷新和事务处理行为是否相同。实际上,以下 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 会出现上述错误。

我想知道为什么。

更新三:

我现在已经从测试中删除了事务注释。

这是测试:

  @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() 操作的那一行。

为什么要寻找节点?为什么它抱怨找不到?既然我正在尝试创建它,难道不应该找不到它吗?

由于您的 Cypher 查询正在使用 MATCH u-[r]-(),如果指定的节点不参与任何关系,它将失败。

您应该改用 OPTIONAL MATCH,这样即使指定的节点不参与任何关系也能使查询成功:

"START u = node({id}) OPTIONAL MATCH u-[r]-() DELETE u,r"

在同一个 t运行saction 中,节点仍然可见,并且由于您的测试很可能是 @T运行sactional 每个方法,tx 仅在方法完成

参见:http://neo4j.com/docs/stable/transactions-delete.html

如果您在删除后添加 t运行sactional 处理(提交),而没有在测试之上添加 @T运行sactional。您应该再也看不到该节点了。

更新

我运行你的测试,正如我解释的那样。

您的测试(通过它的超类)有一个@T运行sactional 注释,因此测试方法中的所有操作都在 one t[=34 中执行=]saction 然后回滚。

如果您想查看真实世界的行为,则必须在 t运行saction 完成后在它自己的 tx 中进行删除(作为您的服务调用的一部分),节点不再可见.

您的断言还测试了先前加载的节点将为 null,但绝不会出现这种情况,因为作为删除操作的一部分,已经存在的变量不会更改。

我从你的测试超类中删除了全局@T运行sactional 注释并将测试方法更改为:

  @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 后,节点消失了。