You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data Neo4j 3.1无法保存关系属性值问题求助

Spring Data Neo4j保存Store时出现NullPointerException问题解决

问题场景

n个商店对应k个商品,希望通过HasProduct关系连接商店与商品,并在该关系上存储商品的qty(数量)和price(价格)(不同商店的属性值不同)。

错误代码实现

@Data
@Node
public class Store {

    @Id
    @GeneratedValue
    private Long id;
    @Property
    private String businessType;
    @Property
    private int currentOnhandInventory;
    @Property
    private String locationId;
    @Property
    @Relationship(type = "HasProduct", value = "HasProduct", direction = Direction.OUTGOING)
    private List<Product> topSellingProducts;
}

@Data
@Node
public class Product {

    @Id
    @GeneratedValue
    private Long id;
    @Property
    private String name;
    @Property
    private String description;
    @Property
    private String department;
    @Property
    @Relationship
    private Store store;

}

@Data
@RelationshipProperties
public class HasProduct {

    @RelationshipId
    @GeneratedValue
    private Long id;

    @Property
    private String qty;

    @Property
    private Double price;

    @TargetNode
    private Product product;

}

@RestController
@RequestMapping("/store")
public class StoreController {

    private StoreRepository storeRepository;
    
    public StoreController(StoreRepository storeRepository) {
        this.storeRepository = storeRepository;
    }

    @PutMapping
    Mono<Store> createOrUpdateStore(@RequestBody Store newStore) {
        return storeRepository.save(newStore);
    }

    @GetMapping
    Mono<Store> getStoreById(@RequestParam Long id) {
        return storeRepository.findById(id);
    }
}

@org.springframework.context.annotation.Configuration
public class Config {

    
    @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
    public ReactiveTransactionManager reactiveTransactionManager(
        Driver driver,
        ReactiveDatabaseSelectionProvider databaseNameProvider) {
        return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider);
    }
    
    @Bean
    public Configuration cypherDslConfiguration() {
        return Configuration.newConfig()
            .withDialect(Dialect.NEO4J_5)
            .build();
    } 
}

public interface StoreRepository extends ReactiveNeo4jRepository<Store, Long> {
    Mono<List<Store>> findOneById(Long id);
}

错误信息

java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "valueToCheck" is null
    at org.springframework.data.neo4j.core.mapping.NestedRelationshipProcessingStateMachine.hasProcessedValue(NestedRelationshipProcessingStateMachine.java:178) ~[spring-data-neo4j-7.1.0.jar:7.1.0]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.FluxPeek] :
    reactor.core.publisher.Flux.checkpoint(Flux.java:3454)
    org.springframework.data.neo4j.core.ReactiveNeo4jTemplate.processNestedRelations(ReactiveNeo4jTemplate.java:1049)

问题分析与解决方案

核心错误点

  1. Store类关系映射错误:topSellingProducts同时标注@Property和@Relationship,且类型为List<Product>——要存储关系属性(qty、price),必须使用关系属性类HasProduct作为集合元素,而非直接关联Product节点。
  2. Product类关系注解错误:store字段错误添加@Property注解,且未指定关系类型与方向,导致双向关系映射混乱。
  3. 关系属性类关联逻辑缺失:HasProduct作为关系属性类,未与Store形成正确的关联映射,导致Spring Data Neo4j无法处理关系数据。

修正后的代码实现

1. Store类修正

@Data
@Node
public class Store {

    @Id
    @GeneratedValue
    private Long id;
    private String businessType; // 默认映射为节点属性,无需@Property
    private int currentOnhandInventory;
    private String locationId;

    // 正确映射带属性的关系:用HasProduct作为集合元素
    @Relationship(type = "HasProduct", direction = Direction.OUTGOING)
    private List<HasProduct> topSellingProducts;
}

2. Product类修正

@Data
@Node
public class Product {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String description;
    private String department;

    // 双向关系:指定反向方向与关系类型
    @Relationship(type = "HasProduct", direction = Direction.INCOMING)
    private List<HasProduct> stores; // 一个商品可被多店持有,用集合更合理
}

3. HasProduct关系属性类修正

@Data
@RelationshipProperties
public class HasProduct {

    @RelationshipId
    @GeneratedValue
    private Long id;

    private String qty; // 默认映射为关系属性,无需@Property
    private Double price;

    @TargetNode
    private Product product;

    // 可选:如需双向关联源节点,添加以下字段
    // @SourceNode
    // private Store store;
}

4. StoreRepository修正

public interface StoreRepository extends ReactiveNeo4jRepository<Store, Long> {
    // 原方法语义矛盾,改为符合规范的查询方法
    Mono<Store> findById(Long id);
}

关键说明

  • 节点类字段默认自动映射为节点属性,无需额外添加@Property(除非属性名与字段名不一致)。
  • 当关系需要存储属性时,必须使用@RelationshipProperties注解的类作为关联类型,不能直接关联节点类。
  • 双向关系需明确指定direction,避免映射冲突。
  • Repository查询方法需符合Spring Data命名规范,避免语义矛盾的方法名。

内容的提问来源于stack exchange,提问作者Abhijeet Mahapatro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:53:21