【问题标题】:Spring Data Neo4j 4: Bug when updating property to null?Spring Data Neo4j 4:将属性更新为空时出现错误?
【发布时间】:2015-12-14 22:10:07
【问题描述】:

我使用 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 会话范围是每个“会话”时会发生此问题,而当会话范围是每个“请求”时不会发生此问题。

@Bean
@Override
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
    return super.getSession();
}

【问题讨论】:

    标签: spring-mvc neo4j spring-data-neo4j-4


    【解决方案1】:

    如果您在 SDN 中使用 HttpSession 范围的持久性,则应确保通过 @ModelAttribute 绑定到控制器的对象与持久层具有相同的范围。使用 Controller 上的@SessionAttribute 注解来实现这一点。

    如果您在 Controller 中使用HttpRequest-scoped 对象和HttpSession-scoped 持久性,您将在 Web 层获得表示同一图形实体的不同对象,这会混淆持久性机制。

    【讨论】:

      【解决方案2】:

      应该不是问题。我刚试过

      @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 的映射上下文是已知的并且得到正确管理。

      【讨论】:

      • 我添加了一个代码示例供您查看在哪种情况下会出现问题。如果您知道如何处理此问题,请告诉我。谢谢。
      • 好的,我明白了。那么在这种情况下,有什么“干净”的方法可以让 Spring MVC @ModelAttribute 与 SDN 一起工作?使用@ModelAttribute注解时会创建新的对象实例然后填充,所以总会导致这个问题...
      猜你喜欢
      • 2018-10-13
      • 1970-01-01
      • 1970-01-01
      • 2015-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-02
      相关资源
      最近更新 更多