Spring Data Neo4j 返回结果包含对象和其余字段时,同名字段取值被对象替换的问题

问题:查询结果Dto中包含复杂对象属性,节点中对应字段存储的为json,在查询使用apoc函数将json转为对象后,疑似替换了本该操作数据,导致字段映射丢失

节点实例
InstanceNode节点示例

接收dto

@Data
public class OperationHistoryDto {

    @Schema(name = "节点名称")
    private String name;

    @Schema(name = "节点候选人")
    private List<UserBaseInfo> candidate;

    @Schema(name = "节点操作人")
    private UserBaseInfo operator;

    @Schema(name = "操作结果", description = "1-待办,2-同意,3-拒绝,4-转发,5-终止")
    private Integer operationResult;

    @Schema(name = "操作备注")
    private String operationRemark;

    @Schema(name = "节点开始时间")
    @JsonFormat(pattern = TimeFormat.DATE_TIME)
    private LocalDateTime beginTime;

    @Schema(name = "节点结束时间")
    @JsonFormat(pattern = TimeFormat.DATE_TIME)
    private LocalDateTime endTime;

    @Schema(name = "节点持续时间")
    private String during;
}

UserBaseInfo

@Data
public class UserBaseInfo {

    @Schema(name = "唯一标识")
    private String id;

    @Schema(name = "名称")
    private String name;
}

查询

    @Query("""
        match (:Instance)-[b:BUSINESS{key:$0}]->(i:InstanceNode)
        with i, case when $1 is null then b.num else $1 end as length
        call apoc.path.expandConfig(i, {
            relationshipFilter: "NEXT>",
            minLevel: length-1,
            maxLevel: length-1,
            limit: 1
        }) yield path
        with nodes(path) as nodes
        unwind nodes as n
        with n
        return n.name as name,
        n.status as operationResult,
        apoc.convert.fromJsonList(n.operationCandidate) as candidate,
        apoc.convert.fromJsonMap(n.operationBy) as operator,
        n.operationRemark as operationRemark,
        n.beginTime as beginTime, n.endTime as endTime,
        n.during as during
    """)
    List<OperationHistoryDto> queryInstanceOperationHistory(String businessKey, Integer num);

首先根据查询日志,确定cypher是没有问题的,neo4j能查询到正确的数据

o.n.d.i.a.i.InboundMessageDispatcher     : [0xd53f5894][localhost:7687][bolt-76] S: SUCCESS {t_first=59, fields=["name", "operationResult", "candidate", "operator", "operationRemark", "beginTime", "endTime", "during"], qid=0}
o.n.d.i.a.i.InboundMessageDispatcher     : [0xd53f5894][localhost:7687][bolt-76] S: RECORD ["发起", 2, NULL, {name: "张三", id: "2"}, NULL, 2024-05-04T15:35:32.924799500, 2024-05-04T15:35:32.929782900, "0S"]
o.n.d.i.a.i.InboundMessageDispatcher     : [0xd53f5894][localhost:7687][bolt-76] S: RECORD ["中间节点1", 2, [{name: "张三", id: "2"}], {name: "张三", id: "2"}, NULL, 2024-05-04T15:35:32.947727200, 2024-05-04T15:38:54.385267300, "3M21S"]
o.n.d.i.a.i.InboundMessageDispatcher     : [0xd53f5894][localhost:7687][bolt-76] S: RECORD ["中间节点2", 2, [{name: "张三", id: "2"}], {name: "张三", id: "2"}, NULL, 2024-05-04T15:38:54.389249100, 2024-05-04T15:49:20.711446100, "10M26S"]
o.n.d.i.a.i.InboundMessageDispatcher     : [0xd53f5894][localhost:7687][bolt-76] S: RECORD ["中间节点3", 2, [{name: "张三", id: "2"}], {name: "张三", id: "2"}, NULL, 2024-05-04T15:49:20.734369500, 2024-05-04T15:50:37.812655400, "1M17S"]
o.n.d.i.a.i.InboundMessageDispatcher     : [0xd53f5894][localhost:7687][bolt-76] S: RECORD ["中间节点4", 2, [{name: "张三", id: "2"}], {name: "张三", id: "2"}, NULL, 2024-05-04T15:50:37.821625400, 2024-05-04T15:57:07.582434300, "6M29S"]
o.n.d.i.a.i.InboundMessageDispatcher     : [0xd53f5894][localhost:7687][bolt-76] S: RECORD ["完成", 2, NULL, {name: "system", id: "system"}, NULL, 2024-05-04T15:57:07.603369, 2024-05-04T15:57:07.775788300, "0S"]

但此时的返回结果中,name被替换成了"张三",beginTime、endTime、during却为空

[
		{
			"name": "张三",
			"candidate": null,
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": null,
			"endTime": null,
			"during": null
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": null,
			"endTime": null,
			"during": null
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": null,
			"endTime": null,
			"during": null
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": null,
			"endTime": null,
			"during": null
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": null,
			"endTime": null,
			"during": null
		},
		{
			"name": "system",
			"candidate": null,
			"operator": {
				"id": "system",
				"name": "system"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": null,
			"endTime": null,
			"during": null
		}
	]

注释掉apoc.convert.fromJsonMap(n.operationBy) as operator后,恢复正常

[
		{
			"name": "发起",
			"candidate": null,
			"operator": null,
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:35:32",
			"endTime": "2024-05-04 15:35:32",
			"during": "0S"
		},
		{
			"name": "中间节点1",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": null,
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:35:32",
			"endTime": "2024-05-04 15:38:54",
			"during": "3M21S"
		},
		{
			"name": "中间节点2",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": null,
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:38:54",
			"endTime": "2024-05-04 15:49:20",
			"during": "10M26S"
		},
		{
			"name": "中间节点3",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": null,
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:49:20",
			"endTime": "2024-05-04 15:50:37",
			"during": "1M17S"
		},
		{
			"name": "中间节点4",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": null,
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:50:37",
			"endTime": "2024-05-04 15:57:07",
			"during": "6M29S"
		},
		{
			"name": "完成",
			"candidate": null,
			"operator": null,
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:57:07",
			"endTime": "2024-05-04 15:57:07",
			"during": "0S"
		}
	]

恢复注释的语句后,将Neo4jRepository<InstanceNode,Long> 替换为Neo4jRepository<Instance,Long>,Instance与UserBaseInfo只有一个name属性同名,此时的查询结果,只有name被替换

[
		{
			"name": "张三",
			"candidate": null,
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:35:32",
			"endTime": "2024-05-04 15:35:32",
			"during": "0S"
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:35:32",
			"endTime": "2024-05-04 15:38:54",
			"during": "3M21S"
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:38:54",
			"endTime": "2024-05-04 15:49:20",
			"during": "10M26S"
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:49:20",
			"endTime": "2024-05-04 15:50:37",
			"during": "1M17S"
		},
		{
			"name": "张三",
			"candidate": [
				{
					"id": "2",
					"name": "张三"
				}
			],
			"operator": {
				"id": "2",
				"name": "张三"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:50:37",
			"endTime": "2024-05-04 15:57:07",
			"during": "6M29S"
		},
		{
			"name": "system",
			"candidate": null,
			"operator": {
				"id": "system",
				"name": "system"
			},
			"operationResult": 2,
			"operationRemark": null,
			"beginTime": "2024-05-04 15:57:07",
			"endTime": "2024-05-04 15:57:07",
			"during": "0S"
		}
	]

暂未查询到具体原因,目前只是猜想在Spring Data Neo4j中,如果返回结果中有包含一个完整的对象和其他数据结果,那么Neo4jRepository设置的类所同名的字段,会被替换为该对象同名字段的值

后续的测试
用Neo4jRepository<Instance,Long>尝试返回一个Version节点,Version与Instance没有任何同名的字段:

	@Query("""
		match (v:Version) return v limit 1
	""")
	Version v();

发现返回结果各字段都为空,可进一步完善猜想(实力有限,没去深挖底层代码):当Cypher直接返回(包含)一个节点或对象时,Neo4jRepository<X,x>会先用X的属性接收对象中的数据,如果此时还有其他返回的零散字段,将会选择X的同名属性,然后转为方法返回对象

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值