2016-06-25 5 views
1

Spring-Data-Neo4J (4.0.0.RELEASE)를 사용하여 응용 프로그램을 빌드하고 있습니다. 응용 프로그램에는 Person 엔티티와 Group 엔티티의 두 엔티티가 있습니다. 또한 관계 엔티티 인 Member_Of가 있습니다.이 엔티티는 사람이 그룹의 구성원임을 나타냅니다. 엔티티는 다음과 같습니다.Neo4J의 두 노드 간의 다중 관계 방지

@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가 돌려 주어 졌을 경우, 즉 관계가 존재하지 않는 경우는 그룹에 추가됩니다.

동일한 사람에게 동일한 사람이 여러 번 추가되는 경우가 종종 있습니다. 이는 두 사람이 응용 프로그램을 실행하고 둘 다 동일한 사용자를 동일한 그룹에 추가하려고 시도 할 때 발생합니다.

어떻게 이런 현상이 발생하지 않도록 할 수 있습니까? 나는 사람과 그룹 사이에 하나의 관계를 가져야하며, 여러 사람이 아닌 하나의 관계를 가질 필요가 있습니다.

답변

1

관계 엔티티의 모든 특성이 동일하다면 주어진 두 엔티티 간에는 하나의 관계 만 작성됩니다. 여기에 범인 인 타임 스탬프가 있습니다. SDN은 두 가지 관계가 속성에 대해 다른 값을 가지며 앞뒤로 진행하여 두 번째 관계를 만들기 때문에 두 관계가 서로 다르다는 것을 인식합니다.

현재 SDN에는 관계 엔터티에 대한 병합 대 제작을 지정할 수있는 구성이 없습니다.

아마도 응용 프로그램 수준에서 일부 동기화를 관리해야 할 것입니다.

+0

구성원의 그룹 가입 시간을 기록하려면 시간 소인이 필요합니다. 나는 중복 관계를 피하기 위해 수표를 지켰습니다. 나는 기존 관계가 있는지를 확인하고 있습니다. 그렇지 않은 경우 멤버 만 추가하십시오. 나는 심지어 모든 방법을 동기화했다. 그러나 여전히 동시 요청을 보내면 중복 관계가 발생합니다. 문제를 어떻게 해결할 수 있습니까? – Soumya

+0

자바 엔티티의 hashtag 및 equals 메소드 구현은 Neo4J에 저장되거나 검색되는 방식에 어떤 영향을 줍니까? equals 메서드가 제대로 구현되지 않았거나 부분적으로 만 구현 된 경우 Neo4j에서 풍부한 관계를 업데이트하는 동안 문제가 있다는 것을 발견했기 때문입니다. 사실, 관계는 후자의 경우 길을 잃고있다. – Soumya

1

나는 동일한 문제가있어서 사용자 지정 암호 쿼리를 사용하여 "해결할"수있었습니다. 성공적으로 사람과 그룹 엔티티는 다음 쿼리를 실행할 수 있습니다 추가 한 점을 감안 :

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

그러나, 당연하게하지 않습니다. 이 방법이 스레드로부터 안전함을 보장하기 위해 광범위한 테스트를 수행하지 않았습니다.

This MERGE의 원자력 실행에 대한 William Lyon의 대답은 여러분이 취해야 할 추가 단계 일 수 있습니다.

+0

나는 이것을 (고유 제한없이) 시도했지만 중복 관계도 생성한다. 우리는 광범위하게 SDN을 사용하고 관계를 생성하는 동안 사이퍼를 사용하는 것은 "http://stackoverflow.com/questions/33461927/creating-relationships-in-neo4j-using-spring-data" – Soumya

관련 문제