Spring Data Neo4j 4:将 属性 更新为 null 时出现错误?
Spring Data Neo4j 4: Bug when updating property to null?
我使用 Spring Data Neo4j 4 GraphRepository 来保存和检索数据。使用 GraphRepository save() 和 findAll() 方法。
当我将现有实体 属性 更新为 null 时,更改似乎没有反映在返回的数据中。
如果我将 属性 更新为任何其他非空值,更改将正确反映。
我可以看到空 属性 更新是在数据库服务器上执行的。但是 findAll() 方法不反映更改并保留旧值。
这是一个已知错误吗?任何解决方法?还是某种缓存问题?
更新
在尝试了解发生了什么之后,我发现当您对同一实体有两个不同的 Java 对象时,就会出现此问题。 null 属性 将永远不会更新(但具有非 null 值的其他属性将会更新)。
示例代码:
@Autowired
MovieRepository repository;
public void test() {
repository.deleteAll();
Movie movie1 = new Movie();
movie1.setName("Pulp Fiction");
movie1.setDirector("Quentin Tarantino");
movie1 = repository.save(movie1);
System.out.println("Movie1: " + movie1);
Movie movie2 = new Movie();
movie2.setId(movie1.getId());
movie2.setName(movie1.getName());
movie2.setDirector(null); // implicit...
movie2 = repository.save(movie2);
System.out.println("Movie2: " + movie2);
Movie movie3 = repository.findOne(movie1.getId());
System.out.println("Movie3: " + movie3);
}
真实案例:当使用具有 Spring MVC 形式的 SDN 时,看起来实体是从模型属性创建的。当表单中的值设置为 null 时,Neo4j 中会正确执行更新,但使用任何 find...() 方法时都不会正确返回值。因此它会导致数据过时。
旁注:当 Neo4J 会话范围为 "session" 时会发生此问题,而当会话范围为 "request".
时不会发生此问题
@Bean
@Override
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
应该完全没有问题。我刚试过
@Test
public void shouldPersistNulls() {
TempMovie movie = new TempMovie( "Pulp Fiction" );
tempMovieRepository.save( movie );
assertSameGraph( getDatabase(), "CREATE (m:Movie {name:'Pulp Fiction'})");
TempMovie loadedMovie = tempMovieRepository.findAll().iterator().next();
loadedMovie.setName(null);
tempMovieRepository.save(loadedMovie);
assertSameGraph( getDatabase(), "CREATE (m:Movie)");
TempMovie loadedAgainMovie = tempMovieRepository.findAll().iterator().next();
assertNull(loadedAgainMovie.getName());
}
它通过了。
根据已编辑的问题进行更新
代表@GraphId 的属性 必须永远不会 手动设置,即通过您的代码。当你需要更新它时,你应该通过 id 加载实体。这可确保实体为 OGM 的映射上下文所知并得到正确管理。
如果您在 SDN 中使用 HttpSession 范围的持久性,您应该确保通过 @ModelAttribute
绑定到控制器的对象具有与持久层相同的范围。在控制器上使用 @SessionAttribute
注释来实现这一点。
如果您在 Controller 中使用 HttpRequest
-scoped 对象和 HttpSession-scoped
持久化,您将在 Web 层获得表示相同图形实体的不同对象,这会混淆持久化机制。
我使用 Spring Data Neo4j 4 GraphRepository 来保存和检索数据。使用 GraphRepository save() 和 findAll() 方法。
当我将现有实体 属性 更新为 null 时,更改似乎没有反映在返回的数据中。
如果我将 属性 更新为任何其他非空值,更改将正确反映。
我可以看到空 属性 更新是在数据库服务器上执行的。但是 findAll() 方法不反映更改并保留旧值。
这是一个已知错误吗?任何解决方法?还是某种缓存问题?
更新
在尝试了解发生了什么之后,我发现当您对同一实体有两个不同的 Java 对象时,就会出现此问题。 null 属性 将永远不会更新(但具有非 null 值的其他属性将会更新)。
示例代码:
@Autowired
MovieRepository repository;
public void test() {
repository.deleteAll();
Movie movie1 = new Movie();
movie1.setName("Pulp Fiction");
movie1.setDirector("Quentin Tarantino");
movie1 = repository.save(movie1);
System.out.println("Movie1: " + movie1);
Movie movie2 = new Movie();
movie2.setId(movie1.getId());
movie2.setName(movie1.getName());
movie2.setDirector(null); // implicit...
movie2 = repository.save(movie2);
System.out.println("Movie2: " + movie2);
Movie movie3 = repository.findOne(movie1.getId());
System.out.println("Movie3: " + movie3);
}
真实案例:当使用具有 Spring MVC 形式的 SDN 时,看起来实体是从模型属性创建的。当表单中的值设置为 null 时,Neo4j 中会正确执行更新,但使用任何 find...() 方法时都不会正确返回值。因此它会导致数据过时。
旁注:当 Neo4J 会话范围为 "session" 时会发生此问题,而当会话范围为 "request".
时不会发生此问题@Bean
@Override
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
应该完全没有问题。我刚试过
@Test
public void shouldPersistNulls() {
TempMovie movie = new TempMovie( "Pulp Fiction" );
tempMovieRepository.save( movie );
assertSameGraph( getDatabase(), "CREATE (m:Movie {name:'Pulp Fiction'})");
TempMovie loadedMovie = tempMovieRepository.findAll().iterator().next();
loadedMovie.setName(null);
tempMovieRepository.save(loadedMovie);
assertSameGraph( getDatabase(), "CREATE (m:Movie)");
TempMovie loadedAgainMovie = tempMovieRepository.findAll().iterator().next();
assertNull(loadedAgainMovie.getName());
}
它通过了。
根据已编辑的问题进行更新
代表@GraphId 的属性 必须永远不会 手动设置,即通过您的代码。当你需要更新它时,你应该通过 id 加载实体。这可确保实体为 OGM 的映射上下文所知并得到正确管理。
如果您在 SDN 中使用 HttpSession 范围的持久性,您应该确保通过 @ModelAttribute
绑定到控制器的对象具有与持久层相同的范围。在控制器上使用 @SessionAttribute
注释来实现这一点。
如果您在 Controller 中使用 HttpRequest
-scoped 对象和 HttpSession-scoped
持久化,您将在 Web 层获得表示相同图形实体的不同对象,这会混淆持久化机制。