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 */
}