我们正在使用Spring Data Neo4j的4.2.0M1版本(目前是最新版本),当我们尝试从父集合中删除链接的子节点然后通过父存储库保存时,我们遇到了一个问题。
模特课程:
@NodeEntity
public class Movie {
@GraphId
private Long graphId;
private String name;
/**
* @return the graphId
*/
public Long getGraphId() {
return graphId;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
@NodeEntity
public class Actor {
@GraphId
private Long graphId;
private String name;
@Relationship(type = "ACTS_IN")
private Set<Movie> movies = new HashSet<>();
/**
* @return the graphId
*/
public Long getGraphId() {
return graphId;
}
/**
* @return the movies
*/
public Set<Movie> getMovies() {
return movies;
}
public void addMovie(Movie movie) {
movies.add(movie);
}
public void removeMovie(Movie movie) {
movies.remove(movie);
}
/**
* @param movies the movies to set
*/
public void setMovies(Set<Movie> movies) {
this.movies = movies;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={RelationAndCacheTest.TestConfiguration.class})
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class RelationAndCacheTest {
@Autowired
private ActorRepository actorRepository;
private static Session neo4jSession;
@Configuration
@EnableAutoConfiguration
@EnableTransactionManagement
@EnableExperimentalNeo4jRepositories("com.xxx")
public static class TestConfiguration {
@Bean
public org.neo4j.ogm.config.Configuration configuration() {
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
config
.driverConfiguration()
.setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver").setURI("http://localhost:7474");
return config;
}
@Bean
public SessionFactory sessionFactory() {
return new SessionFactory(configuration(), "com.xxx") {
@Override
public Session openSession() {
neo4jSession = super.openSession();
return neo4jSession;
}
};
}
@Bean
public Neo4jTransactionManager transactionManager() {
return new Neo4jTransactionManager(sessionFactory());
}
}
@Test
public void relationModificationTest() {
/** Create an actor named Roger and save it => working */
Actor actor = new Actor();
actor.setName("Roger");
actor = actorRepository.save(actor);
/** Create a movie and link it to the actor by saving it through the actor repository => working */
Movie movie = new Movie();
movie.setName("movie");
actor.addMovie(movie);
actor = actorRepository.save(actor);
/** Remove the movie from the actor and save through the actor repository => link not removed !! */
actor.removeMovie((Movie) actor.getMovies().toArray()[0]);
actor.setName("bob");
actor = actorRepository.save(actor);
}
}
该链接不应被删除?这是一个错误吗?有人面临同样的问题吗?
答案 0 :(得分:2)
<强> TL; DR 强>
该问题有两种解决方案:
1)注释测试方法@Transactional
2)每次在任何改变它们的操作之前获取对象。
完整解释
SDN 4.1和SDN 4.2在基础OGM Session
对象方面的行为存在重要差异。
Session对象的主要作用是跟踪您正在执行的操作,以便在您持久保存对象时确定要在图表上执行哪些操作。它本质上是一个缓存,可以在您完成加载,更新和保存对象的循环时跟踪对象的状态。
在SDN 4.1中,Session没有绑定到Spring事务的生命周期。会话在外部建立事务上下文,会话范围(生命周期)通过使用@Scope
注释进行注释来管理,或者通过在需要时以编程方式请求新会话来管理。
在4.2中,Session的生命周期已更改为绑定到发生Repository操作的Spring事务上下文,而后者又与发出请求的线程绑定。为确保此功能始终有效,必须为您创建新的交易(如果尚未启用)。现在,每个新事务都将获得一个新的Session对象。
因此,此代码在4.1中工作而在4.2中不起作用的原因是对ActorRepository的调用之间不再存在任何共享会话。第一次调用存储库的会话信息不适用于第二次(包括关键,哪些关系是新的,哪些关系目前在图中保留),因为它们参与了单独的事务。
4.2的行为发生了变化,因为4.1强制了SDN应用程序的几个限制,以及与Spring框架完全集成的能力。
有关详细信息,请参阅http://graphaware.com/neo4j/2016/09/30/upgrading-to-sdn-42.html,包括从SDN 4.1升级到4.2的步骤