在我的Spring Boot应用程序中,我有一个类似这样的实体类:
public class MyEntity {
String id;
Map<String,String> paramsMap;
//Many members omitted
}
相关的JPA ORM XML片段是
<entity class="MyEntity" access="FIELD">
<table name="myentity">
<!--couple of unique-constraints-->
</table>
<attributes>
<element-collection name="paramsMap" fetch="EAGER">
<collection-table name="my_entity_params">
<join-column name="id" />
</collection-table>
</element-collection>
</attributes>
</entity>
这近似于这个问题的答案
我遇到的问题是MyEntity
类的实体需要更新,包括params
-映射的内容。当这种情况发生时,Oracle DB会返回一个异常,指示违反了表my_entity_params
的主键唯一约束(PostgreSQL无法自动更新某些参数(。
更新方式的近似值是:
public void updateParam(String id, String paramName, String paramValue){
MyEntity old=repository.findById(id)
old.getParamsMap().put(paramName, paramValue);
repository.save(old);
}
其中repository
实现了PagingAndSortingRepository接口。
如果在调用save
之前未修改paramsMap
,则更新成功。我尝试先设置paramsMap
,然后保存实际地图,这导致了同样的错误。
使用one-to-many
将不起作用,因为映射没有指向复杂的类型。类似地,Eclipse基金会wiki的《如何使用ElementCollection映射来映射Basic或Emeddable值的集合》一文并没有阐明如何将元素集合与映射一起使用。
在element-collection
下插入map-key-column
元素似乎可以解决Postgres中的问题,但当连接到Oracle数据库时,问题仍然存在。
如何让Hibernate正确更新地图内容?
我似乎有两个症状相似的问题。
首先,我在element-collection
下缺少元素map-key-column
,因此Spring无法正确构造更新查询。这是通过如下更改元素来修复的:
<element-collection name="paramsMap" fetch="EAGER">
<map-key-column name="my_entity_params_key"/>
<collection-table name="my_entity_params">
<join-column name="id" />
</collection-table>
</element-collection>
第二个问题是Oracle将空字符串视为null,这导致系统进一步混淆,并试图在已经存在键值对的地方插入键值对。这是通过在插入/更新之前从映射中删除空字符串值来修复的。