我正在尝试创建具有可动态属性的特定类型的节点。 例如:我可以创建一个包含名称,年龄,地址属性的Person节点。但是当我创建另一个Person节点时,这些不一定是唯一的属性。此节点可以具有名称,年龄,地址和附加属性工资。使用spring数据或查询DSL需要我创建具有固定数量的实例变量名称,年龄和地址的Java POJO类Person。
@NodeEntity
public class Person {
@GraphId private Long id;
private String name;
private String age;
private String address;
}
我无法为另一个Person节点的工资添加动态属性。有没有办法实现这个目标?
答案 0 :(得分:2)
目前Neo4j-OGM不支持动态属性(参见https://jira.spring.io/browse/DATAGRAPH-555)
如果您只通过OGM与图表进行交互而不必查询单个动态属性,则可以尝试使用自定义Converter的属性Map,将此Map转换为String(如json)。然后,OGM将使用此转换器将图表序列化到图表和从图表序列化。 请注意,因为这些值被压缩为String,所以现在查询单个动态属性并不容易。
要创建custom converter,您需要实现org.neo4j.ogm.typeconversion.AttributeConverter
并提供从Map转换为String的实现。
然后,在您的域实体中注释您的地图属性,如下所示:
@Convert(MoneyConverter.class)
编辑:
正如迈克尔所指出的,如果薪水是唯一的额外可选属性,那么拥有此属性是有意义的,但只有在它有值时才设置它。在这种情况下,动态属性是过度的。如果要使用节点
保留未知和任意属性集,则可能需要使用动态属性答案 1 :(得分:2)
您可以通过创建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 */
}