繁体   English   中英

如何使用 Spring 数据 Neo4j 创建一个与现有节点具有新关系的节点

[英]How can I use Spring Data Neo4j to create a Node with new Relationships to existing Nodes

我的用例是我想通过在两个用户之间创建一个消息节点来将消息从一个用户发送到另一个用户。 这是我想从客户端发送的 JSON,以及我的消息 class:

{"text":"Hello!","recipient":{"userId":"1823498e-e491-45fa-95bb-782a937a00ba"},"sent":{"userId":"6467b976-7ff6-4817-98e0-f3fbfca1413e"}}
@Node("Message")
@Data
public class Message
{   
    @Id @GeneratedValue private UUID messageId; 
    
    @NotNull    
    private String text;
    
    @Relationship(type = "SENT",direction = Direction.INCOMING) 
    private User sent;
    
    @Relationship("TO") 
    private User recipient;
}

但是当我调用Mono<Message> save(Message message); 在 ReactiveNeo4jRepository 中,DB 唯一约束抱怨具有这些用户名的用户已经存在,似乎它正在尝试将这两个 userId 的所有其他属性重置为空/默认值。 大概是因为它们不包含在 JSON 中。所以当它看到两个“FAKE”用户名时,我得到一个约束错误。

2022-03-26 14:34:29.120 DEBUG 51863 --- [o4jDriverIO-2-4] o.n.d.i.a.o.OutboundMessageHandler       : [0xb08eba68][x.server.com:7687][bolt-128] C: RUN "MERGE (user:`User` {userId: $__id__}) SET user += $__properties__ RETURN user" {__id__="6467b976-7ff6-4817-98e0-f3fbfca1413e", __properties__={lastName: NULL, credentialsNonExpired: FALSE,userId: "6467b976-7ff6-4817-98e0-f3fbfca1413e", enabled: FALSE, firstName: NULL, password: "FAKE",accountNonExpired: FALSE, email: NULL,username: "FAKE", accountNonLocked: FALSE}} {bookmarks=["FB:kcwQx2Hl5+KYQJiGdiyzOa4EWSCQ"]}
2022-03-26 14:34:29.206 DEBUG 51863 --- [o4jDriverIO-2-4] o.n.d.i.a.i.InboundMessageDispatcher     : [0xb08eba68][x.server.com:7687][bolt-128] S: SUCCESS {fields=["user"], t_first=2}
2022-03-26 14:34:29.207 DEBUG 51863 --- [o4jDriverIO-2-4] o.n.d.i.a.o.OutboundMessageHandler       : [0xb08eba68][x.server.com:7687][bolt-128] C: PULL {n=-1}
2022-03-26 14:34:29.301 DEBUG 51863 --- [o4jDriverIO-2-4] o.n.d.i.a.i.InboundMessageDispatcher     : [0xb08eba68][x.server.com:7687][bolt-128] S: FAILURE Neo.ClientError.Schema.ConstraintValidationFailed "Node(1) already exists with label `User` and property `username` = 'FAKE'"

更新:我可以直接使用 Jackson 和 Neo4j 驱动程序中的 ObjectMapper 来完成我需要的操作,如下所示。 但我仍然想知道如何使用 SDN。

    @Override
    public Mono<UUID> save(Message message) 
    {
        String cypher = "MATCH (a:User),(b:User) where a.userId = $fromUserId and b.userId = $toUserId CREATE (a)-[:SENT]->(m:Message {messageId: $messageId, text : $text})-[:TO]->(b)";
        Map<String,Object> objMap = persistenceObjectMapper.convertValue(message,mapType);
        return Mono.from(driver.rxSession().writeTransaction(tx -> tx.run(cypher,objMap).records())).then(Mono.just(message.getMessageId()));
    }

似乎它正在尝试将这两个 userId 的所有其他属性重置为空/默认值

您面临的问题根源于传入Message object 的处理。据我了解,您直接使用附加的反序列化User保存Message

您必须先从数据库中获取User SDN 不进行预取。 一种方法是为User实体创建一个额外的存储库。

给定由MovieService调用的 MovieService,您最终会得到如下内容:

@Transactional
public Message saveNewMessage(Message newMessage) {
    UUID recipientId = newMessage.getRecipient().getUserId();
    UUID senderId = newMessage.getSent().getUserId();

    User recipient = userRepository.findById(recipientId).orElseGet(() -> {
        User user = new User();
        user.setName("new recipient");
        return user;
    });

    User sender = userRepository.findById(senderId).orElseGet(() -> {
        User user = new User();
        user.setName("new sender");
        return user;
    });

    newMessage.setRecipient(recipient);
    newMessage.setSent(sender);

    return messageRepository.save(newMessage);
}

对此进行了测试:

CREATE CONSTRAINT username ON (user:User) ASSERT user.name IS UNIQUE

4.3 和/或 4.4

CREATE CONSTRAINT username FOR (user:User) REQUIRE user.name IS UNIQUE

我为您的用例创建了一个示例: https://github.com/meistermeier/neo4j-issues-examples/tree/master/so-71594275我还有一个用户属性擦除调用堆栈 ( /clearusers ) 显示了我的想法发生在你的应用程序中。

编辑:由于我通常建议不要为每个实体 class 创建存储库,因此您也可以使用Neo4jTemplate 我已将saveNewMessageAlternative添加到示例中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM