Spring Data Neo4j (4.2.0.M1) 节点之间的取消链接问题
Spring Data Neo4j (4.2.0.M1) Unlink issue between nodes
我们使用的是 Spring Data Neo4j 的 4.2.0M1 版本(当前最新),当我们尝试从父集合中删除 linked 子节点时遇到问题然后通过父存储库保存。
型号CLASSES:
@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;
}
}
测试 CLASS:
@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);
}
}
link 不应该被删除?这是一个错误吗?有人遇到同样的问题吗?
TL;DR
问题有两种解决方法:
1) 注释测试方法@Transactional
2) 每次在任何改变它们的操作之前获取对象。
完整解释
关于底层 OGM Session
对象,SDN 4.1 和 SDN 4.2 的行为存在重要差异。
Session 对象的主要作用是跟踪您正在执行的操作,以便在您持久化对象时确定要对图形执行哪些操作。它本质上是一个缓存,在您经历加载、更新和保存对象的循环时跟踪对象的状态。
在 SDN 4.1 中,会话未绑定到 Spring 事务的生命周期。会话是在外部事务上下文中建立的,会话范围(生命周期)是通过使用@Scope
注释对其进行注释,或者在需要时以编程方式请求新会话来管理的。
在 4.2 中,会话的生命周期已更改为绑定到发生存储库操作的 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 的步骤
我们使用的是 Spring Data Neo4j 的 4.2.0M1 版本(当前最新),当我们尝试从父集合中删除 linked 子节点时遇到问题然后通过父存储库保存。
型号CLASSES:
@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;
}
}
测试 CLASS:
@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);
}
}
link 不应该被删除?这是一个错误吗?有人遇到同样的问题吗?
TL;DR
问题有两种解决方法:
1) 注释测试方法@Transactional
2) 每次在任何改变它们的操作之前获取对象。
完整解释
关于底层 OGM Session
对象,SDN 4.1 和 SDN 4.2 的行为存在重要差异。
Session 对象的主要作用是跟踪您正在执行的操作,以便在您持久化对象时确定要对图形执行哪些操作。它本质上是一个缓存,在您经历加载、更新和保存对象的循环时跟踪对象的状态。
在 SDN 4.1 中,会话未绑定到 Spring 事务的生命周期。会话是在外部事务上下文中建立的,会话范围(生命周期)是通过使用@Scope
注释对其进行注释,或者在需要时以编程方式请求新会话来管理的。
在 4.2 中,会话的生命周期已更改为绑定到发生存储库操作的 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 的步骤