neo4j java 节点动态属性
neo4j java node dynamic properties
我正在尝试创建具有动态属性的特定类型的节点。
例如:我可以创建一个具有名称、年龄、地址属性的 Person 节点。但是当我创建另一个 Person 节点时,这些不一定是唯一的属性。该节点可以有姓名、年龄、地址和额外的 属性 薪水。使用 spring 数据或查询 DSL 需要我创建 Java POJO class Person with fixed number of instance variables name,age and address .
@NodeEntity
public class Person {
@GraphId private Long id;
private String name;
private String age;
private String address;
}
我无法为另一个 Person 节点的工资添加动态 属性。有什么办法可以实现吗?
Neo4j-OGM 目前不支持动态属性(参见 https://jira.spring.io/browse/DATAGRAPH-555)
如果您仅通过 OGM 与您的图表交互,而不必查询单个动态属性,您可以尝试使用自定义转换器的属性映射,将此映射转换为字符串(如 json).然后 OGM 将使用此转换器将地图序列化为图表。
请注意,因为这些值被压缩成一个字符串,所以现在查询单个动态 属性.
并不是一件容易的事
要创建 custom converter,您需要实施 org.neo4j.ogm.typeconversion.AttributeConverter
并提供从 Map 转换为 String 的实施。
然后,在您的域实体中注释您的地图 属性,如下所示:
@Convert(MoneyConverter.class)
编辑:
正如 Michael 所指出的,如果薪水是唯一的额外可选 属性,那么拥有这个 属性 是有意义的,但只有在它有值时才设置它。在这种情况下,动态属性是多余的。当您有一组未知的和任意的属性要与节点一起保存时,您可能希望使用动态属性
您可以通过创建 CompositeAttributeConverter 保存图表中的每个动态 属性 来解决这些限制(不仅因为 JSON-String 无法很好地查询 - 如 luanne 所述在接受的答案中)
import java.lang.reflect.Field;
import java.util.*;
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
public abstract class DynamicPropertiesConverter implements CompositeAttributeConverter<Map<String, ?>> {
private Set<String> blacklist;
public DynamicPropertiesConverter(Class<?> clazz) {
blacklist = new HashSet<>();
addAllFields(clazz);
}
public DynamicPropertiesConverter(Set<String> blacklist) {
this.blacklist = blacklist;
}
public void addAllFields(Class<?> type) {
for (Field field : type.getDeclaredFields()) {
blacklist.add(field.getName());
}
if (type.getSuperclass() != null) {
addAllFields(type.getSuperclass());
}
}
@Override
public Map<String, ?> toGraphProperties(Map<String, ?> value) {
Map<String, ?> result = new HashMap<>(value);
result.keySet().removeAll(blacklist);
return result;
}
@Override
public Map<String, ?> toEntityAttribute(Map<String, ?> value) {
return toGraphProperties(value);
}
}
现在您可以创建此转换器的特殊版本:
public class DynamicNodePropertiesConverter extends DynamicPropertiesConverter {
public DynamicNodePropertiesConverter() {
super(Node.class);
}
}
并像这样使用它:
import java.util.Map;
import DynamicNodePropertiesConverter;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.typeconversion.Convert;
@NodeEntity
public class Node {
@Convert(DynamicNodePropertiesConverter.class)
private Map<String, Object> data;
/* getter and setter */
}
我正在尝试创建具有动态属性的特定类型的节点。 例如:我可以创建一个具有名称、年龄、地址属性的 Person 节点。但是当我创建另一个 Person 节点时,这些不一定是唯一的属性。该节点可以有姓名、年龄、地址和额外的 属性 薪水。使用 spring 数据或查询 DSL 需要我创建 Java POJO class Person with fixed number of instance variables name,age and address .
@NodeEntity
public class Person {
@GraphId private Long id;
private String name;
private String age;
private String address;
}
我无法为另一个 Person 节点的工资添加动态 属性。有什么办法可以实现吗?
Neo4j-OGM 目前不支持动态属性(参见 https://jira.spring.io/browse/DATAGRAPH-555)
如果您仅通过 OGM 与您的图表交互,而不必查询单个动态属性,您可以尝试使用自定义转换器的属性映射,将此映射转换为字符串(如 json).然后 OGM 将使用此转换器将地图序列化为图表。 请注意,因为这些值被压缩成一个字符串,所以现在查询单个动态 属性.
并不是一件容易的事要创建 custom converter,您需要实施 org.neo4j.ogm.typeconversion.AttributeConverter
并提供从 Map 转换为 String 的实施。
然后,在您的域实体中注释您的地图 属性,如下所示:
@Convert(MoneyConverter.class)
编辑:
正如 Michael 所指出的,如果薪水是唯一的额外可选 属性,那么拥有这个 属性 是有意义的,但只有在它有值时才设置它。在这种情况下,动态属性是多余的。当您有一组未知的和任意的属性要与节点一起保存时,您可能希望使用动态属性
您可以通过创建 CompositeAttributeConverter 保存图表中的每个动态 属性 来解决这些限制(不仅因为 JSON-String 无法很好地查询 - 如 luanne 所述在接受的答案中)
import java.lang.reflect.Field;
import java.util.*;
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
public abstract class DynamicPropertiesConverter implements CompositeAttributeConverter<Map<String, ?>> {
private Set<String> blacklist;
public DynamicPropertiesConverter(Class<?> clazz) {
blacklist = new HashSet<>();
addAllFields(clazz);
}
public DynamicPropertiesConverter(Set<String> blacklist) {
this.blacklist = blacklist;
}
public void addAllFields(Class<?> type) {
for (Field field : type.getDeclaredFields()) {
blacklist.add(field.getName());
}
if (type.getSuperclass() != null) {
addAllFields(type.getSuperclass());
}
}
@Override
public Map<String, ?> toGraphProperties(Map<String, ?> value) {
Map<String, ?> result = new HashMap<>(value);
result.keySet().removeAll(blacklist);
return result;
}
@Override
public Map<String, ?> toEntityAttribute(Map<String, ?> value) {
return toGraphProperties(value);
}
}
现在您可以创建此转换器的特殊版本:
public class DynamicNodePropertiesConverter extends DynamicPropertiesConverter {
public DynamicNodePropertiesConverter() {
super(Node.class);
}
}
并像这样使用它:
import java.util.Map;
import DynamicNodePropertiesConverter;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.typeconversion.Convert;
@NodeEntity
public class Node {
@Convert(DynamicNodePropertiesConverter.class)
private Map<String, Object> data;
/* getter and setter */
}