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 层获得表示相同图形实体的不同对象,这会混淆持久化机制。