JPA - @OneToMany as a Map
Asked Answered
C

2

25

This seems like a common enough case, but as JPA newbie, I am having trouble figuring this out. I'm using EclipseLink and PostgreSQL, but this should relate to just the JPA spec.

I have one table PRIMARY that has an ID and then a bunch of other columns. There is another table SECONDARY that has a foreign key into the PRIMARY table also called ID. This SECONDARY table has a composite key of that ID and a varchar representing a locale.

So, in the Primary entity I want to have a field of type Map<String, Secondary> where the key is the locale string from the SECONDARY table and the entry is the Secondary entity. My Secondary class looks like this:

@Entity
public class Secondary
{
     @Id
     private Long id;
     @Id
     private String locale;
     private String str1;
     private String str2;
     .....
}

I'm thinking I want to use the @MapKeyJoinColumn annotation, but I can't seem to get the other annotations to work. I tried this:

@OneToMany
@JoinColumn(name="ID")
@MapKeyJoinColumn(name="LOCALE")
private Map<String, Secondary> secondaryByLocale;

This resulted in it trying to select a column named secondaryByLocale_key which doesn't exist.

I then tried this:

@OneToMany
@JoinTable(name="SECONDARY", 
        joinColumns={@JoinColumn(name="ID")},
        inverseJoinColumns=@JoinColumn(name="ID"))
@MapKeyJoinColumn(name="LOCALE")
private Map<String, Secondary> secondaryByLocale;

This results in the following error:

Exception Description: The @JoinColumns on the annotated element [field secondaryByLocale] from the entity class [class com.foo.Primary] is incomplete. When the source entity class uses a composite primary key, a @JoinColumn must be specified for each join column using the @JoinColumns. Both the name and the referencedColumnName elements must be specified in each such @JoinColumn.

I tried adding the referencedColumnName to the annotation (I wasn't sure what it even should be), but I got the same error.

As suggested, I tried using @MapKey as follows:

@OneToMany
@JoinColumn(name="ID")
@MapKey(name="LOCALE")
private Map<String, Secondary> secondaryByLocale;

This results in the following error:

Exception Description: The map key [LOCALE] on the entity class [class com.foo.Secondary] could not be found for the mapping [org.eclipse.persistence.mappings.UnidirectionalOneToManyMapping[secondaryByLocale]].

Maybe I'm going about this all wrong, and there's a better way to annotate the Map field. Any help would be much appreciated.

Cornaceous answered 3/8, 2012 at 5:14 Comment(0)
B
23

Try using @MapKey(name = "locale") instead.

@MapKeyJoinColumn is used when your map key is an entity, but here you're just using the locale String.

Basifixed answered 3/8, 2012 at 5:28 Comment(6)
If that doesn't work, can you post the code for your Secondary class?Basifixed
I've updated the question with the Secondary code and the results from trying @MapKeyCornaceous
I've updated my answer - your entity attribute is called "locale" not "LOCALE"...Basifixed
Also, are you sure it's valid to have two @Id fields on your Secondary entity?Basifixed
Interesting, I haven't had any problems with case sensitivity before, but that definitely fixes it. Also, the two @Id annotations seem to work just fine. Thanks so much for your help!Cornaceous
Great :-) With case sensitivity, you'll have mixed results when you're referring to table column names but here you're referring to a class property (to be used as a Map key) so definitely case sensitive.Basifixed
P
1

In my case, it is worked with @OneToMany(cascade=CascadeType.PERSIST) @MapKeyColumn(name="COLUMN_NAME")

or

You can directly try with only @OneToMany(cascade=CascadeType.PERSIST)

Philipp answered 20/9, 2019 at 13:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.