【问题标题】:Prevent Multiple Relationships between two nodes in Neo4J防止 Neo4J 中两个节点之间的多重关系
【发布时间】:2016-06-25 04:31:29
【问题描述】:

我正在使用 Spring-Data-Neo4J (4.0.0.RELEASE) 构建应用程序。该应用程序有两个实体,一个 Person 实体和一个 Group 实体。还有一个关系实体,Member_Of,它表示一个人是一个组的成员。实体如下所示

@NodeEntity(label="Person")
public class Person {
   protected String uuid;
   protected String fullName;
   protected String email;

   @Relationship(type = RelationshipNames.MEMBER_OF, direction = Relationship.OUTGOING)
   protected List<GroupMembership> groupMemberships = new ArrayList<GroupMembership>() ;
}

@NodeEntity(label="Group")
public class Group implements Serializable{
   protected static final long serialVersionUID = 1L;

   @GraphId
   protected Long id;
   protected String uuid;
   protected String name;

   @Relationship(type = RelationshipNames.MEMBER_OF, direction = Relationship.INCOMING)
   protected List<GroupMembership> groupMemberships = new ArrayList<GroupMembership>() ;
}

@RelationshipEntity(type = RelationshipNames.MEMBER_OF)
public class GroupMembership implements Serializable{
   private static final long serialVersionUID = 1L;

   @GraphId Long id;
   @Property String uuid; 
   @StartNode Person member;
   @EndNode Group group;
   @DateLong
   Date date;
}

有一种方法可以将成员添加到组中。该方法使用@Transactional 进行注释。示例代码如下。

@Override
@Transactional(propagation=Propagation.REQUIRED)
public ResponseEntity<GroupVO> addMembersToGroup(String groupUuid, String personUuid, List<String> personsToAdd){
   Group group = groupRepository.findGroupByUuid(groupUuid);
   List<Person> personsToAdd = IterableUtils.toList(personRepository.findPersonsByUuid(personUuids));

    personsToAdd.forEach(personToAdd -> {
        GroupMembership existingGroupMembership = getActiveMembership(group.getUuid(), personToAdd.getUuid());
        if(existingGroupMembership==null){
            GroupMembership newGroupMembership = new GroupMembership(personToAdd, group, GroupRoleNames.MEMBER, member.getUuid(), new Date());
            personToAdd.getGroupMemberships().add(newGroupMembership);
            group.getGroupMemberships().add(newGroupMembership);
   }
   groupRepository.save(group);
}

它试图做的是,它搜索 personToAdd 和组之间的现有关系。如果返回null,即不存在关系,则将其添加到组中。

问题有时是同一个人被多次添加到同一组中。当两个人正在运行应用程序并且他们都试图将同一个人添加到同一个组时,就会发生这种情况。

如何防止这种情况发生?我需要在一个人和组之间建立一个单一的关系,而不是多个关系。

【问题讨论】:

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


    【解决方案1】:

    如果关系实体上的所有属性都相等,则两个给定实体之间只会创建一个关系。您有一个时间戳,这是罪魁祸首 - SDN 意识到这两种关系不同,因为它们具有不同的属性值并继续创建第二个关系。

    目前,SDN 没有允许您为关系实体指定合并与创建的配置。

    您可能必须在应用程序级别管理一些同步。

    【讨论】:

    • 需要时间戳来记录成员加入群组的时间。我一直在检查以避免重复的关系。我正在检查是否存在任何现有关系。如果没有,那么只添加一个成员。我什至同步了整个方法。但是仍然发送并发请求会导致重复关系。我该如何解决这个问题?
    • java 实体的 hashtag 和 equals 方法的实现如何影响(如果有的话)它们在 Neo4J 中存储或检索的方式?因为我发现如果equals方法没有正确实现或者只是部分实现了,在Neo4j中更新丰富的关系时会出现问题。实际上,在后一种情况下,关系正在迷失。
    【解决方案2】:

    我遇到了同样的问题,并且能够通过使用自定义密码查询“解决”它。鉴于您已成功添加 Person 和 Group 实体,您可以运行以下查询:

     @Query("MATCH (group:Group) " +
            "MATCH (person:Person) " +
            "WHERE person.uuid={0} AND group.uuid={1} "+
            "MERGE (person)-[r:MEMBER_OF]->(group) " +
            "SET r.uuid ={2} , r.date={3} " +
            "RETURN r")
    GroupMembership isMemberOf(String personUuid,String groupUuid, String uuid, Date date);
    

    这样称呼它:

    personRepository.isMemberOf(personUuid,groupUuid,uuid,date);
    

    然而,不要想当然。我没有进行大量测试来确保这种方法是线程安全的。

    ThisWilliam Lyon 关于 MERGE 原子执行的回答可能是您必须采取的额外步骤。

    【讨论】:

    • 我试过这个(没有唯一约束),但它也创建了重复的关系。正如“stackoverflow.com/questions/33461927/…”中所说,我们不鼓励在创建关系时使用 SDN 并使用 cypher。
    猜你喜欢
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    • 2018-04-09
    • 2013-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多