spring-data-neo4j basic one-to-many relationship not persisting

匿名 (未验证) 提交于 2019-12-03 08:54:24

问题:

EDIT: Sample project available on github.

I'm using Neo4J (Rest graph database, hosted in grapheneDb) and Spring Data in our backend project.

<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringCypherRestGraphDatabase"> 

I have a simple one-to-many relationship between two entities: User and Stay.

EDIT: I thought this wasn't relevant for the issue, but after seeing a similar problem in SDN4, I think I need to update the question (there is a basic @NodeEntity class, and both entities are extending this base class).

@NodeEntity public abstract class BasicNodeEntity implements Serializable {     @GraphId    private Long nodeId; }   public class User extends BasicNodeEntity {    @RelatedTo(type = "HAS_STAY",  direction = Direction.OUTGOING)   Set<Stay> stays;    public void addStay(Stay stay) {      stays.add(stay);   } }  public class Stay extends BasicNodeEntity {     @RelatedTo(type = "HAS_STAY", direction = Direction.INCOMING)    User user; } 

I'm unable to persist more than one stay. The first stay I add to the user is persisted correctly, but just the first one. The next stays added never persists, and I always retrieve the first one.

The method I use to create a new stay is:

   @Autowired    Neo4jOperations template;     @Transactional    private void createStay(Stay stay, User user) throws Exception {       stay = template.save(stay);       user.addStay(stay);       template.save(user);       // If i evaluate user at this point, it contains both stays        // But if I retrieve the user from the repository, it just contains       // the first stay, the second one has not persisted.    } 

EDIT: User modified is retrieved correctly through UserRepository.

public interface UserRepositoryCustom {}  public interface UserRepository extends GraphRepository<User>, UserRepositoryCustom {        User findById(String id); }  User user = userRepository.findById(userId); 

NOTE: I also tried to save through the repository interface instead of the Neo4jTemplate one, but I have the same problem.

Both entities are correctly saved in the neo4j database, it's just a persistence issue.

I think this should be quite easy, so I'm probably missing something..

Any help would be greatly appreciated.

Relevant versions:

<spring.version>4.0.5.RELEASE</spring.version> <spring-data-neo4j.version>3.3.2.RELEASE</spring-data-neo4j.version> 

There is another SO question with a very similar problem, but without response so far.

回答1:

It is a tricky thing.

Your custom equals method causes two entities which have their node-id set but not yet their uuid-id set, to be equal so that when loading them into a set the set will only contain one.

Code in: RelationshipHelper

protected Set<Object> createEntitySetFromRelationshipEndNodes(Object entity, final MappingPolicy mappingPolicy, final Class<?> relatedType) {     final Iterable<Node> nodes = getStatesFromEntity(entity);     final Set<Object> result = new HashSet<Object>();     for (final Node otherNode : nodes) {         Object target = template.createEntityFromState(otherNode, relatedType, mappingPolicy);         result.add(target);     }     return result; } 

If you change your code to have an equals/hashcode in your BasicNode entity:

   @Override    public boolean equals(Object o) {       if (this == o) return true;       if (!(o instanceof BasicNodeEntity)) return false;        BasicNodeEntity that = (BasicNodeEntity) o;        if (nodeId != null) {          if (!nodeId.equals(that.nodeId)) return false;       } else {          if (that.nodeId != null) return false;       }        return true;    }     @Override    public int hashCode() {       return nodeId != null ? nodeId.hashCode() : 0;    } 

so that entities that have only a nodeId set are comparable

and adapt the subclass methods

   @Override    public boolean equals(Object o) {       if (this == o) return true;       if (!(o instanceof IdentifiableEntity)) return false;        IdentifiableEntity entity = (IdentifiableEntity) o;       //change       if (!super.equals(o)) return false;        if (id != null) {          if (!id.equals(entity.id)) return false;       } else {          if (entity.id != null) return false;       }        return true;    }     @Override    public int hashCode() {       //change       if (super.hashCode() != 0) return super.hashCode();       return id != null ? id.hashCode() : 0;    } 

Then it works.

Going forward if you are working with Neo4j Server I recommend to you to check out SDN 4 RC2 instead which was released on Friday.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!