Search code examples
hibernatemappinghibernate-mappinghibernate-onetomany

Hibernate : OneToMany mapping not based on PK?


I have 2 entities/tables.

One is a proper entity, let's call it data. It has a number of fields containing so-called "multilingual codes".

The second table, code, contains the multilingual values themselves.

Here is some example data :

Data table
id  name         continentCode  countryCode 
------------------------------------
1   Toto         EU             CH
2   Titi         AS             CN

Code table
id  code   language  text
----------------------------
1   EU     EN        Europe
2   EU     FR        Europe
3   EU     DE        Europa
4   CH     EN        Switzerland
5   CH     FR        Suisse
6   CH     DE        Schweiz
... etc

I would like to map the properties continents, countries etc in the Data entity as a Map, like that :

@OneToMany()
@MapKey(name="languageCode")
private Map<String, Code> continents;

So that I can then read the text for the right language like that :

Data toto = dao.findByName("Toto");
String text = toto.getContries.get("FR").getText(); //--> returns "Suisse"
String text = toto.getContries.get("EN").getText(); //--> returns "Switzerland"

I also need to be able to make text search on the values of these "codes", using the language of the user. (e.g. get all datas where the country='suisse', in French !)

So, is it possible to map a OneToMany collection using a key field that is not the primary key of the current entity ? I need my continents collection "all records from the Code table where the code = the value of my continentCode property". Or maybe there is a more appropriate way of representing this kind of relationship ?

NB : Unfortunately I can't change the SQL schema...


Solution

  • OK, I found the solution. The OneToMany mapping on my Data entity looks like that :

    @OneToMany()
    @JoinColumn(name="code", referencedColumnName="continentCode", insertable=false, updatable=false)   
    @MapKey(name="languageCode")
    private Map<String, AAGeoContinentThesaurusEntry> continents;
    

    I also had to map the continentCode column in order for it to work. I fi didn't do it, I got a :

    org.hibernate.MappingException: Unable to find column with logical name: GCH_CDE_CODE_CNT in org.hibernate.mapping.Table
    (GCHDATA) and its related supertables and secondary tables
            at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:396)
            at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:102)
    

    Now I can do :

    myData.getContinentCodes().get("FR").getText() 
    

    and receive the string "Europe" :)