防止Neo4J中两个节点之间的多个关系

时间:2016-06-25 04:31:30

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

我正在使用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,即不存在任何关系,则将其添加到组中。

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

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

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

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

 @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);

然而,不要把它视为理所当然。我还没有做过大量测试,以确保这种方法是线程安全的。

William Lyon关于MERGE原子执行的回复{p> This可能是你必须采取的额外步骤。