【问题标题】:Unable to change or delete relationship between nodes with Neo4j OGM and Spring Boot Data无法使用 Neo4j OGM 和 Spring Boot Data 更改或删除节点之间的关系
【发布时间】:2018-04-11 19:24:30
【问题描述】:

我在使用 Spring Boot (v1.5.10) 和 Neo4j OGM (v2.1.6,带有 Spring Data Neo4j v4.2.10) 删除或更改两个节点之间的现有关系时遇到问题。我发现一些使用旧版 Neo4j OGM 版本(如 1.x.something)的人报告的类似问题的痕迹,但我认为,随着 2.1.6 和最新的 Spring Boot v1 版本,它应该早已不复存在。因此,我不知道这是回归还是我没有以正确的方式使用 API。

所以,我的节点实体定义如下:

@NodeEntity
public class Task {

    @GraphId
    private Long id;
    private String key;

    @Relationship(type = "HAS_STATUS")
    private Status status;

    public Task() {
    }

    public Long getId() {
        return id;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }
}

@NodeEntity
public class Status {

    @GraphId
    private Long id;
    private String key;

    @Relationship(type = "HAS_STATUS", direction = Relationship.INCOMING)
    private Set<Task> tasks;

    public Status() {
        tasks = new HashSet<>();
    }

    public Long getId() {
        return id;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Set<Task> getTasks() {
        return tasks;
    }

    public void addTask(Task task) {
        tasks.add(task);
    }

    public boolean removeTask(Task task) {
        if(this.hasTask(task)) {
            return this.tasks.remove(task);
        }
        return false;
    }

    public boolean hasTask(Task task) {
        return this.tasks.contains(task);
    }
}

这是它可以用类似 Cypher 的样式表示的方式:

(t:Task)-[:HAS_STATUS]->(s:Status)

这是尝试更新任务状态的 Service 方法:

public void updateTaskStatus(Task task, Status status) {
    Status prevStatus = task.getStatus();
    if(prevStatus != null) {
        prevStatus.removeTask(task);
        this.saveStatus(prevStatus);
    }

    task.setStatus(status);
    if(status != null) {
        status.addTask(task);
        this.saveStatus(status);
    }

    this.saveTask(task);
}

作为更新的结果,我得到了两个 HAS_STATUS 关系到两个不同的状态节点(旧的和新的),或者,如果我尝试删除现有的关系,什么也没有发生(旧的关系仍然存在)

可以在 GitHub 上找到说明问题的完整演示:

https://github.com/ADi3ek/neo4j-spring-boot-demo

非常欢迎任何可以帮助我解决该问题的线索或建议! :-)

【问题讨论】:

标签: java spring-boot spring-data-neo4j spring-data-neo4j-4 neo4j-ogm


【解决方案1】:

如果您使用@Transactional 注释您的命令(因为这是加载实体的位置),它将起作用。 潜在的问题是,如果您加载一个实体,它将打开一个带有新会话(上下文)的新事务,查找关系并在上下文中缓存有关它们的信息。然后事务(和会话)将关闭,因为操作已完成。

随后的保存/更新没有找到打开的事务,因此会打开一个新事务(带有新的会话/会话上下文)。执行保存时,它会查看处于当前状态的实体,不再查看旧关系。

两个答案:

  1. 这是一个错误 ;(

编辑:经过几天的思考,我恢复了上面的陈述。这不是真正的错误,而更像是意外行为。 SDN没有错。它使用两个会话(每个操作一个)来完成工作,并且由于没有人告诉它在一个事务中完成工作,因此加载的对象不是“托管”或“附加”(如在 JPA 中)到会话上下文。

  1. 您可以通过为您的工作单元使用显式事务来解决此问题

我将关闭 SDN 的 issue,并尝试将所有信息迁移到 GitHub 上的两个 issue 之一,因为这是一个 OGM 问题。

【讨论】:

  • 谢谢@meistermeier,我在@Transactional 注释上玩了一下,但不是在命令方法上,我会检查该方法并报告
  • 现在可以使用了。在命令方法中添加@Transactional 解决了这个问题:github.com/ADi3ek/neo4j-spring-boot-demo/commit/…
  • 太棒了。感谢您的耐心等待;)
  • @meistermeier 究竟是什么必须标记为@Transactional
猜你喜欢
  • 2018-11-23
  • 2018-03-16
  • 1970-01-01
  • 2016-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多