如何使用Spring Data Neo4j创建与现有节点具有新关系的节点

x33g5p2x  于 2022-11-05  发布在  Spring
关注(0)|答案(1)|浏览(240)

我的用例是,我想通过在两个用户之间创建一个Message节点,从一个用户向另一个用户发送一条消息。下面是我想从客户端发送的JSON,以及我的Message类:
第一个
但是当我在ReactiveNeo 4jRepository中调用Mono<Message> save(Message message);时,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的ObjectMapper和Neo4j驱动程序来完成我所需要的,如下所示。但是我仍然想知道如何使用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()));
    }
wko9yo5t

wko9yo5t1#

它似乎试图将这两个userId的所有其他属性重置为空/默认值
您所面临的问题的根源在于对传入Message对象的处理。据我所知,您直接保存了Message和附加的、反序列化的User
您必须先从数据库中提取User。SDN不会进行预提取。一种方法是为User实体创建一个额外的存储库。
给定一个由控制器调用的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),它显示了我认为在应用程序中发生的事情。
编辑:因为我通常建议不要为每个实体类都创建一个仓库,所以您也可以使用Neo4jTemplate

相关问题