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

时间:2015-09-15 16:30:12

标签: neo4j spring-data-neo4j

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

我正在使用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()操作的那个。

为什么要查找节点?为什么抱怨没找到?不应该找不到,因为我正在尝试创建它?

2 个答案:

答案 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之后,节点就消失了。