将 null 存储为实体 属性 的值?

Storing null as value of Entity Property?

由于实体存储在存储空值时抛出,我设法得到一个 "hack" 来将空值保存到其中。但是我不确定我的方法是否徒劳。

这是一个片段:

entityStore.executeInTransaction(new StoreTransactionalExecutable() {
                @Override
                public void execute(@NotNull final StoreTransaction txn) {

                    try {
                        entityStore.registerCustomPropertyType(txn, UndefinedIterable.class, UndefinedBinding.BINDING);
                    } catch (Exception e) {

                    }

                    final Entity entity = txn.newEntity(storeName);
                    Iterator<String> it = comparableMap.keySet().iterator();
                    while (it.hasNext()) {
                        String key = it.next();
                        Comparable value = comparableMap.get(key);
                        if(value == null) {
                            entity.setProperty(key, new UndefinedIterable());
                        } else {
                            entity.setProperty(key, value);
                        }
                    }

这里的第一个问题是,一遍又一遍地 registerCustomPropertyType 是否安全,因为每次服务器收到 POST 请求时都会调用此方法。

接下来这里还需要UndefinedIterable吗?

完整代码如下

UndefinedIterable.java

public class UndefinedIterable implements Serializable, ByteIterable {

    private byte[] bytes;

    public UndefinedIterable() {
        bytes = "null".getBytes();
    }

    @Override
    public ByteIterator iterator() {
        return new ArrayByteIterable(bytes).iterator();
    }

    @Override
    public byte[] getBytesUnsafe() {
        return bytes;
    }

    @Override
    public int getLength() {
        return bytes.length;
    }

    @NotNull
    @Override
    public ByteIterable subIterable(int offset, int length) {
        return null;
    }

    @Override
    public int compareTo(@NotNull ByteIterable o) {
        return 0;
    }
}

UndefinedBinding.java

public class UndefinedBinding extends ComparableBinding {

    public static final UndefinedBinding BINDING = new UndefinedBinding();

    @Override
    public Comparable readObject(@NotNull ByteArrayInputStream stream) {
        try {
            byte[] serialized = ByteStreams.toByteArray(stream);
            Comparable deserialized = deserialize(serialized, Comparable.class);
            return deserialized;
        } catch (Exception e) {

        }
        return null;
    }

    @Override
    public void writeObject(@NotNull LightOutputStream output, @NotNull Comparable object) {
        byte[] serialized = serialize(object);
        output.write(serialized);
    }

    public static byte[] serialize(Object obj) {
        try {
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
                 ObjectOutput out = new ObjectOutputStream(bos)) {
                out.writeObject(obj);
                return bos.toByteArray();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        try {
            ByteArrayInputStream in = new ByteArrayInputStream(data);
            ObjectInputStream is = new ObjectInputStream(in);
            return (T) is.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

}

恐怕我的方法对于保存 null 值这样简单的工作来说有点矫枉过正?

registerCustomPropertyType 几次是安全的,尽管通常在初始化阶段调用一次。

如果我真的需要区分缺少 属性 值和 属性 具有空值,那么我会尝试定义非空值来替换空值。对于 String,它可以是 UUID 的十六进制表示。对于IntegerInteger.MIN_VALUEInteger.MAX_VALUE等,不要对单个属性使用混合类型的值,否则按属性值或范围搜索不行。