Cannot merge node using null 属性 value for uuid in Spring Data Neo4j starter 和 OGM SessionFactory 的原因是什么?

What is the cause of Cannot merge node using null property value for uuid in Spring Data Neo4j starter and OGM SessionFactory?

显然这是一个常见的例外,但是,这里提出的所有问题似乎都与 CSV 有关,因此,为什么要问这个问题。

我有一个 domain 对象,它使用 uuid 作为唯一 ID,声明如下

@NodeEntity(label = "TNODE")
public class TestNode {
    @Id @GeneratedValue(strategy = UuidStrategy.class) 
    @Convert(UuidStringConverter.class)
    private UUID uuid;

    private String name; 

    @Relationship(type = "TEST_REL_IS", direction = Relationship.OUTGOING) private TestNodeTarget testTarget;

    public TestNode() {}
    public TestNode(String name, TestNodeTarget target) {
        this.name = name; 
        this.testTarget = target;
    }

    //getters and setters
}

TestNodeTarget如下

@NodeEntity(label = "TNODE_TARGET")
public class TestNodeTarget {
    private Long id; 
    private String name;

    public TestNodeTarget() {}
    public TestNodeTarget(String name) {
        this.name = name; 
    }

    //getters and setters
}

我正在使用 Spring Boot 2.0.3.RELEASEsprng-boot-data-neo4j 启动器,它可以拉下 neo4j-ogm-core-3.1.0neo4j-ogm-bolt-driver-3.1.0neo4j-ogm-api-3.1.0 和神秘的 neo4j-java-driver-1.5

我正在使用 Neo4j OGM SessionFactory 构建我自己的通用 DAO 层,而不是 Spring 限制我使用

的数据存储库

问题

我能够执行 CREATEREADDELETE 操作。具有以下假设的 PUT 操作

  1. 之前创建了 tn:TestNodet1:TestNodeTargett2:TestNodeTarget
  2. tn节点与t1节点有关系
  3. 检索tn个节点,t1 & t2个节点
  4. tn 节点关系从 t1 更改为 t2
  5. 呼叫session.save

例外是

Caused by: org.neo4j.driver.v1.exceptions.ClientException: Cannot merge node using null property value for uuid
    at org.neo4j.driver.internal.util.ErrorUtil.newNeo4jError(ErrorUtil.java:62)
    at org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher.handleFailureMessage(InboundMessageDispatcher.java:137)
    at org.neo4j.driver.internal.messaging.PackStreamMessageFormatV1$Reader.unpackFailureMessage(PackStreamMessageFormatV1.java:432)
    at org.neo4j.driver.internal.messaging.PackStreamMessageFormatV1$Reader.read(PackStreamMessageFormatV1.java:396)
    at org.neo4j.driver.internal.async.inbound.InboundMessageHandler.channelRead0(InboundMessageHandler.java:83)
    at org.neo4j.driver.internal.async.inbound.InboundMessageHandler.channelRead0(InboundMessageHandler.java:35)
    at org.neo4j.driver.internal.shaded.io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284)
    at org.neo4j.driver.internal.async.inbound.MessageDecoder.channelRead(MessageDecoder.java:40)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:297)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:413)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at org.neo4j.driver.internal.shaded.io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1336)
    at org.neo4j.driver.internal.shaded.io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1127)
    at org.neo4j.driver.internal.shaded.io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1162)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
    at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at org.neo4j.driver.internal.shaded.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at org.neo4j.driver.internal.shaded.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935)
    at org.neo4j.driver.internal.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
    at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
    at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
    at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
    at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
    at org.neo4j.driver.internal.shaded.io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:858)
    at org.neo4j.driver.internal.shaded.io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)

问题

  1. 错误 Caused by: org.neo4j.driver.v1.exceptions.ClientException: Cannot merge node using null property value for uuid 消息的根本原因是什么?节点 uuid 值不为空。
  2. bolt-driverneo4j-java-driver 如何相互通信?我很惊讶地看到 neo4j-java-driver
  3. 因为我使用 Neo4j OGM 支持 Spring 数据的 Repository 那么我可以放弃 spring-boot-starter-data-neo4j 吗?如果是,@Transactional 和事务管理会怎样?

TL;DR

使用带有 @Id 注释的 UUID 字段不能替代 private Long id 字段(或者是吗?)。将 id 字段添加到 class 中,异常消失。

我迫不及待地决定自己调试这个问题并分享我的发现

交易

起初,PUT 操作(没有 private Long id 字段)无一例外地工作但未能删除旧关系,基于此 Github issue 我将操作包装在 @Transactional 我得到了例外。一些进展。

ORM 上下文中,上面的方法可以正常工作。换句话说,我可以 retrieve 来自 @Transactional 注释服务层的实体,在 non-transactional 层中进行必要的更改,然后 persist 使用另一个服务层方法的实体用 @Transactional 注释。对于 OGM,您必须在同一事务层中完成所有操作。哼!

异常

如上述问题所示,TestNode 实体使用 UUID 如下

@Id @GeneratedValue(strategy = UuidStrategy.class) 
@Convert(UuidStringConverter.class)
private UUID uuid;

我必须更新 TestNode class 以包含

private Long id; 

在此之后,PUT 操作按预期工作,旧关系被删除。

困惑

为什么缺少private Long id;只会导致更新时出现异常?为什么不在 retrievedeletecreate 实体时呢?