如何使用Hibernate持久化HashMap

6

你好,我非常新于Hibernate世界,并似乎遇到了一个难题。我需要存储的对象中有一个哈希映射表。

private Map<String, SentimentFrequencyCounts> modelData = null;

事实上,我永远不需要搜索、排序或对这个地图做任何操作,我只需要将它与对象一起保存,并在加载对象时加载它,因此我希望有一种方法让Hibernate将其序列化,然后将其存储在CLOB或BLOB字段中,但我似乎找不到任何方法来做到这一点。
所以我接下来尝试让Hibernate这样保存。
    @OneToMany(mappedBy="ngram_data", fetch = FetchType.EAGER) 
 @MapKey(name = "attributeName") 
 public Map<String, SentimentFrequencyCounts> getModelData() {
  return modelData;
 }

但是这让我在运行时得到以下异常:org.hibernate.AnnotationException: 使用@OneToMany或@ManyToMany针对未映射的类:

SentimentFrequencyCounts类是我尝试持久化的一个内部类。所以基本上我认为我真的不理解hibernate如何处理hashmap。真的很遗憾我不能只序列化它并将其合并到单个列中。

提前感谢您的帮助和时间。


你如何映射“SentimentFrequencyCounts”?它是一个单独的实体吗?还是一个组合体? - Jeremy
我有一个SentimentFrequencyCount(它是可序列化的),被标记为@Embeddable,但我也尝试将其作为实体,但没有成功。 - JNR
2个回答

5
@org.hibernate.annotations.Type(
        type = "org.hibernate.type.SerializableToBlobType", 
        parameters = { @Parameter( name = "classname", value = "java.util.HashMap" ) }
)
public Map<String, SentimentFrequencyCounts> getModelData() {
  return modelData;
}

在大多数情况下,仅使用以下代码就可以解决问题(分布式缓存可能会有问题):

@org.hibernate.annotations.Type( type = "org.hibernate.type.SerializableType" )
public Map<String, SentimentFrequencyCounts> getModelData() {
  return modelData;
}

我使用了你的第一个选项,它有效了!我可以持久化一个Map,并且也能检索到它。第二个选项不行,堆栈跟踪显示它找不到org.hibernate.type.Serializable,尽管这个类在类路径中。不知道怎么回事。¯\(ツ) - geekonablog
1
哎呀,那是因为第二个包含了一个打字错误。应该是 org.hibernate.type.SerializableType,而不仅仅是 org.hibernate.type.Serializable。我已经在上面修复了这个问题。 - Steve Ebersole
这个解决方案对我来说非常完美,特别是第一个例子。谢谢! - bezbos.

3

将现有的注释去掉,并使用 @Lob 注释列表 - 这 指定持久化属性或字段应该作为数据库支持的大型对象类型进行持久化

如果变量的类型是 Serializable 的子类型,则可以完全省略注释;JPA 的默认映射规则指出,Serializable 且不是基本类型或 Embeddable 的类型会被序列化并存储在 BLOB 列中。但是,List 不是 Serializable,即使 ArrayList 是。

您可以将 @Lob 与 @ElementCollection 一起使用,但我不确定结果是什么;我不知道是否将整个列表序列化,还是创建一个表,其中每个列表元素单独序列化。无论如何,这可能对您都没有兴趣。

远期编辑:当然,遵循规范的勤奋学生会知道,此注释仅适用于 Serializable 类型 的字段,而不是仅仅持有 Serializable 对象的字段。因此,为了使其工作,你必须进行诡计。我看了看是否能用有界通配符交集类型做些聪明的事情,但我不认为可以。但是,您可以编写一个像这样的小类:

class SerializableInstanceOf<T> implements Serializable {
    public final T instance;

    public SerializableInstanceOf(T instance) {
        Serializable s = (Serializable)instance;
        this.instance = instance;
    }
}

将其用作列表的容器-实体具有一个标记为@Lob的此类型字段,并在其中保留对列表的引用。每次您想要使用列表时,都需要通过实例字段,可能是通过实体上的getList方法进行。

这很丑陋,但它应该让您做您需要做的事情。


我认为这是一般正确的解决方案,但我遇到了java.util.HashMap无法转换为java.sql.Blob异常,HashMap和我的键值类都是可序列化的,所以我不确定为什么它不能将其转换。但再次感谢您指出正确的方向。 - JNR
@JNR:结果发现我的答案是错误的。请参阅EJB 3.0持久性规范的2.1.1节 - 开头的段落“实体的持久字段或属性可以是以下类型”。该段落实际上不允许使用Map类型的字段。你可能需要声明为HashMap。很糟糕。我不确定还能做什么。 - Tom Anderson
Eclipselink可以解决这个问题。我想知道为什么Hibernate没有序列化对象,这是预期的行为。 - Ralph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接