Spring Data Neo4j基本的一对多关系不会持久化

4

编辑: 在github上有示例项目可供参考。

我们的后端项目中使用了Neo4J(Rest图形数据库,托管在grapheneDb中)和Spring Data。

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

我有两个实体之间的简单一对多关系:UserStay编辑:我认为这与问题无关,但在SDN4中看到了一个类似的问题后,我认为需要更新问题(有一个基本的@NodeEntity类,两个实体都扩展了这个基类)。
@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;
}

我无法持续超过一个逗留时间。我添加到用户的第一个逗留时间被正确地持久化,但只有第一个逗留时间。添加的下一个逗留时间从不持久化,我总是检索到第一个逗留时间。
我用来创建新逗留时间的方法是:
   @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.
   }
编辑:通过UserRepository正确检索到修改后的用户。
public interface UserRepositoryCustom {}

public interface UserRepository extends GraphRepository<User>, UserRepositoryCustom {    
   User findById(String id);
}

User user = userRepository.findById(userId);

注意:我也尝试通过存储库接口而不是Neo4jTemplate来保存,但是出现了相同的问题。

这两个实体都正确保存在neo4j数据库中,只是一个持久性问题。

我认为这应该很容易,所以我可能错过了什么...

任何帮助将不胜感激。

相关版本:

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

有另一个类似问题的SO问题,但迄今没有回应。


你从哪里获得要添加入住的用户?它是否已经在集合中有了第一次入住? - Michael Hunger
嗨,Michael!感谢您的评论。请查看我的编辑:用户通过neo4j存储库正确检索,并且是第一个停留点。我正在使用SpringCypherRestGraphDatabase(托管在grapheneDB中)。 - troig
1
但是这些停留点是两个不同的吗?你认为你能为这个设置创建一个小的测试用例吗? - Michael Hunger
1
嗨,Michael。我已经在Github上创建了一个示例项目,其中包含错误。希望这能对你有所帮助。感谢你的时间! - troig
1
嗨@MichaelHunger!你有没有机会看一下示例项目?如果示例不够清晰,请告诉我。再次感谢。 - troig
显示剩余2条评论
1个回答

2

这是一个棘手的问题。

你的自定义equals方法会导致两个实体在节点ID已设置但UUID ID尚未设置时相等,因此将它们加载到集合中时,集合只会包含一个实体。

代码位于: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;
}

如果您修改代码,在BasicNode实体中增加equals/hashcode方法:
   @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;
   }

为了使只有nodeId设置的实体可比较

并调整子类方法

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

然后它就可以工作了。

如果您打算使用Neo4j Server进行工作,我建议您查看上周五发布的SDN 4 RC2


非常感谢Michael,完美的捕捉!我无法指出正确的方向。我已经在我们的项目中尝试过了,它的效果非常好。我们计划切换到SDN4,感谢你的建议。 - troig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接