Динамические свойства узла neo4j java

Я пытаюсь создать узлы определенного типа со свойствами, которые могут быть динамическими. Например: я могу создать узел Person со свойствами имени, возраста, адреса. Но это не обязательно должны быть единственные свойства, когда я создаю другой узел Person. Этот узел может иметь имя, возраст, адрес и дополнительную собственность. Используя данные весны или запрос DSL, мне нужно создать класс Java POJO Person с фиксированным количеством переменных имени, возраста и адреса экземпляра.

@NodeEntity
public class Person {
@GraphId private Long id;

private String name;
private String age;
private String address;
}

Я не могу добавить динамическое свойство для зарплаты для другого узла Person. Есть ли способ добиться этого?


person Manu Bhat    schedule 30.06.2016    source источник
comment
но атрибуты являются необязательными, вам не нужно их устанавливать.   -  person Michael Hunger    schedule 30.06.2016


Ответы (2)


Динамические свойства в настоящее время не поддерживаются в Neo4j-OGM (см. https://jira.spring.io/browse/DATAGRAPH-555)

Если вы взаимодействуете со своим графиком только через OGM и вам не нужно запрашивать отдельные динамические свойства, вы можете попробовать карту свойств с помощью специального преобразователя, который преобразует эту карту в строку (например, json). Затем OGM будет использовать этот преобразователь для сериализации карты в график и обратно. Обратите внимание, что поскольку значения сжаты в строку, теперь не так просто запросить отдельное динамическое свойство.

Чтобы создать пользовательский преобразователь вам нужно реализовать org.neo4j.ogm.typeconversion.AttributeConverter и предоставить реализацию для преобразования из Map в String. Затем аннотируйте свойство карты в объекте домена следующим образом:

 @Convert(MoneyConverter.class)

Редактировать:

Как указал Майкл, если зарплата является единственным дополнительным необязательным свойством, то имеет смысл иметь это свойство, но устанавливать его только тогда, когда оно имеет значение. Динамические свойства в этом случае излишни. Вы можете захотеть использовать динамические свойства, когда у вас есть неизвестный и произвольный набор свойств, которые должны быть сохранены с узлом.

person Luanne    schedule 30.06.2016
comment
Спасибо за ответ. Не могли бы вы указать мне пример для этого пользовательского конвертера? - person Manu Bhat; 30.06.2016
comment
Большое спасибо. Позвольте мне попробовать это. На самом деле в примере, который я привел, в качестве одного дополнительного поля была только зарплата, но реальный вариант использования действительно с неизвестным и произвольным набором свойств. - person Manu Bhat; 01.07.2016

Вы можете обойти ограничения, создав 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 Andreas Berger    schedule 06.03.2017