0

In my Spring Boot application, I have an entity class like this:

public class MyEntity {
    String id;
    Map<String,String> paramsMap;
    //Many members omitted
}

And the relevant JPA ORM XML snippet is

<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>

This approximates the answer to this question

The problem I have is that entities of class MyEntity need to be updated, including the contents of the params-map. When this happens, Oracle DB returns an exception indicating the primary key-unique constraint of table my_entity_params has been violated (PostgreSQL silently fails to update some of the params).

An approximation of how the update happens is:

public void updateParam(String id, String paramName, String paramValue){
    MyEntity old=repository.findById(id)
    old.getParamsMap().put(paramName, paramValue);
    repository.save(old);
}

Where repository implements the interface PagingAndSortingRepository.

If paramsMap isn't modified before calling save, the update succeeds. I have tried first setting the paramsMap, saving and then saving the actual map, which has resulted in the same error.

Using one-to-many won't work because the map doesn't point to a complex type. In a similar vein, Eclipse foundation wiki's How to map collections of Basic or Emeddable values using an ElementCollection mapping article doesn't shed light on how to use element-collection with a map.

Inserting a map-key-column element under element-collection seems to fix the issue in Postgres, but the issue remains when connected to an Oracle database.

How do I get Hibernate to update the map contents correctly?

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Haem
  • 929
  • 6
  • 15
  • 31
  • In the answer you are quoting, key/name and value are mapped using "MapKeyColumn" and "Column", there are no equivalent in your xml mapping. – Tristan Dec 13 '18 at 13:18
  • I see. How would I approximate those in the xml? – Haem Dec 13 '18 at 13:19
  • Well, in the doc I guess : https://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/MapKeyColumns#Example_of_a_map_key_column_relationship_XML – Tristan Dec 13 '18 at 13:24
  • @Tristan I tried that, and got a build error (I think it's from an in-house schema exporter) `org.hibernate.annotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class: my.domain.MyEntity.paramsMap[java.lang.String]` – Haem Dec 13 '18 at 13:39
  • You should update your question with the new things you are trying, including annotations, xml, and table description. – Tristan Dec 13 '18 at 14:04

1 Answers1

0

It appears I had two problems with similar symptoms.

First, I was missing the element map-key-column from under element-collection, so Spring couldn't construct the update query correctly. This was fixed by changing the element like this:

<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>

The second problem is that Oracle treats empty strings as null, which caused the system to get further confused and attempt to insert key-value pairs where a key-null pair already existed. This was fixed by removing the empty string values from the map prior to insert/update.

Haem
  • 929
  • 6
  • 15
  • 31