繁体   English   中英

hibernate 实体上的参数化构造函数

[英]Parameterized constructor on hibernate entity

TL;博士

有什么方法可以干净地将一些 arguments 传递给休眠实例化的 object 后加载?

我有的

@Entity
public class MyEntity {
    @Lob
    private String mapAsJson;

    @Transient
    private Map<Long, Double> map = new HashMap<>();

    // Getters, null-checks, and all that. Always keeping these two in sync, or at least before it persists
}

我想要的是

@Entity
public class MyEntity {
    @Embedded
    private MyEmbedded<Long, Double> embeddedMap = new MyEmbedded<>();
}

@Embeddable
public class MyEmbedded<K, V> {
    @Lob
    private String mapAsJson;
    @Transient
    private final Map<K, V> map = new HashMap<>();

    @PreUpdate @PrePersist
    private void storeAsJson() {
        // JsonUtil encapsulates com.fasterxml.jackson.databind.ObjectMapper logic
        mapAsJson = JsonUtil.toString(map);
    }

    @PostLoad
    private void loadFromJson() {
        map.clear();
        if (mapAsJson != null) 
            // JsonUtil encapsulates com.fasterxml.jackson.databind.ObjectMapper logic
            map.putAll(JsonUtil.fromString(mapAsJson, HashMap.class));
    }
}

为什么我想要它

只是为了很好地封装这个工作 map object 的水合作用。 如果我还有 2 个像这样的其他字段,那将是很多重复的代码。 当然,这是一个非常具体的示例,但它可以扩展到 map 以外的其他对象。

为什么它不起作用

这个JsonUtil.fromString(mapAsJson, HashMap.class)基本上是在猜测类型。 它目前返回<String, Integer>的 map ,但我实际上需要Double

可能失败的解决方案 #1

这当然不起作用,因为 hibernate 不知道我的嵌入式 object 参数是什么。

@Entity
public class MyEntity {
    @Embedded
    private MyEmbedded<Long, Double> embeddedMap = new MyEmbedded<>(Long.class, Double.class);
}

@Embeddable
public class MyEmbedded<K, V> {
    @NotNull
    private Class<K> keyClass;
    @NotNull
    private Class<V> valClass;

    protected MyEmbedded() {

    }

    public MyEmbedded(Class<K> keyClass, Class<V> valClass) {
        this.keyClass = keyClass;
        this.valClass = valClass;
    }

    // [...]

    @PostLoad
    private void loadFromJson() {
        map.clear();
        if (mapAsJson != null)
            // NOTICE THIS DIFFERENT LINE
            map.putAll(JsonUtil.fromString(mapAsJson, HashMap.class, keyClass, valClass));
    }
}

可能的解决方案#2

@Embeddable
public class MyEmbedded<K, V> {
    @NotNull
    private Class<K> keyClass;
    @NotNull
    private Class<V> valClass;

    // [...]

    // Call this in the entity once, on the embedded. Maybe on @PostLoad?
    public MyEmbedded<K, V> init(Class<K> keyClass, Class<V> valClass) {
        this.keyClass = keyClass;
        this.valClass = valClass;
    }
}

由于您进一步指定JsonUtil是自己的 class,我建议为JsonUtil.fromString使用以下签名:

public static <K, V> Map<K, V> fromString(String json, Class<K> keyClass,
        Class<V> valueClass, @SuppressWarnings("rawtypes") Class<? extends Map> mapClass) {
// ...

这样,您返回的 map 将被推断为正确的类型,并且您可以使用您的“我想要的”变体。 对于委托给该方法的其他不太庞大的访问,您可以使用不同的命名签名:

public static <V> Map<V> fromStringLongKey(String json,
        Class<V> valueClass, @SuppressWarnings("rawtypes") Class<? extends Map> mapClass) {
    return fromString(json, Long.class, valueClass, mapClass);
}
//...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM