我正在编写一个应用程序来捕获其他应用程序的配置属性. Config是我的主要域对象. Config对象之间存在层次关系(一个Config [:OVERRIDES]另一个Config).因此,给定最底层的Config,我需要在层次结构中一直到最顶层的Config,并沿途收集Config对象的所有属性,将它们合并到一个最终的Config中.但我不知道如何使用
Spring Data做到这一点.
以下是2个Config对象的架构:
CREATE (c1:Config {name:'ConfigParent'});
SET c2.docker_tag='1.0.0';
SET c2.mem_limit='1gb';
MATCH (c1:Config {name: 'ConfigParent'})
CREATE (c2:Config {name:'ConfigChild'})-[:OVERRIDES]->(c1)
SET c2.docker_tag='1.0.1';
ConfigChild属性需要与ConfigParent合并,并且将覆盖ConfigParent中的任何重复属性.所以我的最后一组属性应该是:
name='ConfigMerged' //I don't know what this name would be?
docker_tag='1.0.1'
mem_limit='1gb'
Config中可以有任意键/值对,因此不能按名称返回它们.我已经使用了这个CQL,我想我做了我想要的:
MATCH p = SHORTESTPATH((c2:Config)<-[:OVERRIDES*]-(c1:Config))
WHERE c1.name = 'ConfigChild' and not (c2)-[:OVERRIDES]->()
UNWIND NODES(p) as props return PROPERTIES(props);
JSON响应如下所示:
[
{
"keys": [
"properties(props)"
],
"length": 1,
"_fields": [
{
"name": "ConfigParent",
"docker_tag": "1.0.0",
"mem_limit": "1gb"
}
],
"_fieldLookup": {
"properties(props)": 0
}
},
{
"keys": [
"properties(props)"
],
"length": 1,
"_fields": [
{
"name": "ConfigChild",
"docker_tag": "1.0.1"
}
],
"_fieldLookup": {
"properties(props)": 0
}
}
]
问题是,我不知道如何将其映射到POJO.我是否需要Config域对象或属性域对象?这是实现我目标的最佳CQL吗?
更新:我已经为Config提出了一个带注释的POJO.但是当我尝试在代码中返回它时,属性总是空的,以及parentConfig.
@NodeEntity
public class Config {
@Id
@GeneratedValue
private Long id;
@Relationship(type = "OVERRIDES")
private Config parentConfig;
@Properties(allowCast=true)
private Map<String, String> properties;
....
}
这是我正在测试的基本查询,只是为了看看我是否可以映射到POJO:
@Query("MATCH (c1:Config) RETURN c1;")
List<Config> findConfigAny(@Param("configName") String configName);
最佳答案 您接近解决方案,但Neo4j-OGM(Spring Data Neo4j中用于对象图映射的库)存在技术限制:使用@Properties注释时,它只会持久化并加载前缀(默认属性名称)使用正确的分隔符(默认值).所以基本上在你的情况下它只会加载以属性为前缀的属性.而不是所有的回报.
在Spring Data Neo4j中,还可以提供可以被视为DTO的@QueryResult.您可以使用注释标记中间类.请确保此类也是实体扫描的一部分.
@QueryResult
public class ConfigDto {
private String name;
private Map<String, String> properties;
}
如果您将SDN存储库方法的返回类型也更改为此类型
@Query("MATCH p = SHORTESTPATH((c2:Config)<-[:OVERRIDES*]-(c1:Config))"
+ " WHERE c1.name = 'Child' and not (c2)-[:OVERRIDES]->()"
+ " UNWIND NODES(p) as props return props.name as name, PROPERTIES(props) as properties")
List<ConfigDto> configs();
而且使用此方法,它将返回:
ConfigDto{name='Child', properties={a.exclusive=1, name=parentConfig, a.override=parent value}}
ConfigDto{name='Child', properties={a.exclusiveChild=my value, name=Child, a.override=child value}}
请注意,我编写了一个测试,其中包含一个“原始”Config对象的持久性,该对象具有上面映射的属性,我只是用它们作为前缀.您可以看到该名称也在查询返回的属性映射中,因此map包含节点的所有属性.
编辑(从评论中保存部分)
通过上述解决方案,可以从Neo4j加载现有数据.
除了@Properties解决方案之外,不可能保留任意属性,但这会在图形中创建“带前缀”,“分隔”属性.例如.使用您的问题中的代码,您将获得properties.docker_tag.
例如,您可以为Map编写自己的属性转换器,并从https://github.com/neo4j/neo4j-ogm/blob/master/core/src/main/java/org/neo4j/ogm/typeconversion/MapCompositeConverter.java开始定位并获取一些想法
以下是转换器documentation的链接,您应该实现CompositeAttributeConverter.
Neo4j-OGM并不打算一直使用更改属性名称,如果域类本身中存在nameA属性并且也在这样的属性映射中定义,则决定保存的内容也很复杂.