neo4j java节点动态属性

时间:2016-06-30 11:38:01

标签: neo4j querydsl spring-data-neo4j-4 neo4j-ogm

我正在尝试创建具有可动态属性的特定类型的节点。 例如:我可以创建一个包含名称,年龄,地址属性的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节点的工资添加动态属性。有没有办法实现这个目标?

2 个答案:

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