2

I have an entity with the following mapping defined:

@ElementCollection(fetch=FetchType.LAZY, targetClass=MyEntityTranslations.class)
@CollectionTable(name="MY_ENTITY_TRANSLATIONS", joinColumns=@JoinColumn(name="PARENT_ID"))
@MapKeyColumn(name="LOCALE")
private Map<String, MyEntityTranslations> translations;

The MyEntityTranslations class looks like this:

@Embeddable
public class MyEntityTranslations
{
    @Column(name="NAME")
    private String name;
    @Column(name="DESCRIPTION")
    private String description;

    public MyEntityTranslations()
    {
    }

    //getters and setters
}

The MY_ENTITY_TRANSLATIONS table looks like this:

CREATE TABLE MY_ENTITY_TRANSLATIONS
(
  parent_id bigint NOT NULL,
  locale character varying NOT NULL,
  name character varying,
  description character varying,
  CONSTRAINT my_entity_translations_pkey PRIMARY KEY (parent_id, locale)
);

Everything works fine and as expected, but when I update the name or description in MyEntityTranslations it is doing a DELETE followed by an INSERT instead of just an UPDATE.

I thought maybe adding equals() and hashCode() methods to MyEntityTranslations would allow JPA to know if it should simply be updated. However, I quickly realized I don't have the information necessary in MyEntityTranslations to properly override those methods.

After googling around about this issue, I found plenty of places for this problem with a List, with the solution being adding an @OrderColumn annotation or changing it to a Set. However, I couldn't find anything about this for a Map.

Really, after a record is inserted into the MY_ENTITY_TRANSLATIONS table, it will never need to be deleted unless the entity with the id equal to the PARENT_ID column is deleted. Is there anything I can do with either the entity or the embeddable that will allow JPA to always do UPDATEs instead of the DELETE/INSERT behavior?

In case it makes a difference, I'm using PostgreSQL, Spring Data JPA, and EclipseLink.

dnc253
  • 39,967
  • 41
  • 141
  • 157

1 Answers1

0

You are using both the parent_id and locale as the primary key, but there is no way to tell JPA that information with an Embeddable: Update requires that constructs have something that uniquely identifies them, so that JPA can distinguish them apart from one another and track changes on. Embeddable is the complete opposite of that, stating that these constructs do not have their own identifier and so use their parents ID alone.

What you should be doing is making MyEntityTranslations an entity using the parent_id, locale fields as the primary key, so your model then matches what you have setup in the database.

Chris
  • 20,138
  • 2
  • 29
  • 43
  • 1
    I understand what you're saying, but I was hoping to avoid having the MyEntityTranslations be an entity. The translations only exist as part of the entity, and I want the entity to be responsible for populating the map. Is there something other than @Embeddable that I can put on MyEntityTranslations? – dnc253 Jul 29 '15 at 22:43