Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

EclipseLink/Examples/JPA/2.0/MapKeyColumns

How to use Map key columns to map complex Maps

JPA 2.0 allows for a Map where the key is not part of the target object to be persisted. The Map key can be any of the following:

  • A Basic value, stored in the target's table or join table.
  • An Embedded object, stored in the target's table or join table.
  • A foreign key to another Entity, stored in the target's table or join table.

Map columns can be used for any collection mapping including, OneToMany, ManyToMany and ElementCollection.

This allows for great flexibility and complexity in the number of different models that can be mapped. The type of mapping used is always determined by the value of the Map, not the key. So if the key is a Basic but the value is an Entity a OneToMany mapping is still used. But if the value is a Basic but the key is an Entity a ElementCollection mapping is used.

This allows some very sophisticated database schemas to be mapped. Such as a three way join table, can be mapped using a ManyToMany with a MapKeyJoinColumn for the third foreign key. For a ManyToMany the key is always stored in the JoinTable. For a OneToMany it is stored in the JoinTable if defined, otherwise it is stored in the target Entity's table, even though the target Entity does not map this column. For an ElementCollection the key is stored in the element's table.

The @MapKeyColumn annotation or <map-key-column> XML element is used to define a map relationship where the key is a Basic value, the @MapKeyEnumerated and @MapKeyTemporal can also be used with this for Enum or Calendar types. The @MapKeyJoinColumn annotation or <map-key-join-column> XML element is used to define a map relationship where the key is an Entity value, the @MapKeyJoinColumns can also be used with this for composite foreign keys. The annotation @MapKeyClass or <map-key-class> XML element can be used when the key is an Embeddable or to specify the target class or type if generics are not used.

Example of a map key column relationship database

EMPLOYEE (table)

ID FIRSTNAME LASTNAME SALARY
1 Bob Way 50000
2 Sarah Smith 60000

PHONE(table)

ID OWNER_ID PHONE_TYPE AREACODE NUMBER
1 1 home 613 792-7777
2 1 cell 613 798-6666
3 2 home 416 792-9999
4 2 fax 416 798-5555

Example of a map key column relationship annotation

@Entity
public class Employee {
  @Id
  private long id;
  ...
  @OneToMany(mappedBy="owner")
  @MapKeyColumn(name="PHONE_TYPE")
  private Map<String, Phone> phones;
  ...
}
 
@Entity
public class Phone {
  @Id
  private long id;
  ...
  @ManyToOne
  private Employee owner;
  ...
}

Example of a map key column relationship XML

<entity name="Employee" class="org.acme.Employee" access="FIELD">
    <attributes>
        <id name="id"/>
        <one-to-many name="phones" mapped-by="owner">
            <map-key-column name="PHONE_TYPE"/>
        </one-to-many>
    </attributes>
</entity>
<entity name="Phone" class="org.acme.Phone" access="FIELD">
    <attributes>
        <id name="id"/>
        <many-to-one name="owner"/>
    </attributes>
</entity>

Example of a map key join column relationship database

EMPLOYEE (table)

ID FIRSTNAME LASTNAME SALARY
1 Bob Way 50000
2 Sarah Smith 60000

PHONE(table)

ID OWNER_ID PHONE_TYPE_ID AREACODE NUMBER
1 1 1 613 792-7777
2 1 2 613 798-6666
3 2 1 416 792-9999
4 2 3 416 798-5555

PHONETYPE(table)

ID TYPE
1 home
2 cell
3 fax
4 work

Example of a map key join column relationship annotation

@Entity
public class Employee {
  @Id
  private long id;
  ...
  @OneToMany(mappedBy="owner")
  @MapKeyJoinColumn(name="PHONE_TYPE_ID")
  private Map<PhoneType, Phone> phones;
  ...
}
 
@Entity
public class Phone {
  @Id
  private long id;
  ...
  @ManyToOne
  private Employee owner;
  ...
}
 
@Entity
public class PhoneType {
  @Id
  private long id;
  ...
  @Basic
  private String type;
  ...
}

Example of a map key join column relationship XML

<entity name="Employee" class="org.acme.Employee" access="FIELD">
    <attributes>
        <id name="id"/>
        <one-to-many name="phones" mapped-by="owner">
            <map-key-join-column name="PHONE_TYPE_ID"/>
        </one-to-many>
    </attributes>
</entity>
<entity name="Phone" class="org.acme.Phone" access="FIELD">
    <attributes>
        <id name="id"/>
        <many-to-one name="owner"/>
    </attributes>
</entity>
<entity name="PhoneType" class="org.acme.PhoneType" access="FIELD">
    <attributes>
        <id name="id"/>
        <basic name="type"/>
    </attributes>
</entity>


Example of a map key class embedded relationship database

EMPLOYEE (table)

ID FIRSTNAME LASTNAME SALARY
1 Bob Way 50000
2 Sarah Smith 60000

EMPLOYEE_PHONE (table)

EMPLOYEE_ID PHONE_ID TYPE
1 1 home
1 2 cell
2 3 home
2 4 fax

PHONE (table)

ID AREACODE NUMBER
1 613 792-7777
2 613 798-6666
3 416 792-9999
4 416 798-5555

Example of a map key class embedded relationship annotation

@Entity
public class Employee {
  @Id
  private long id;
  ...
  @OneToMany
  @MapKeyClass(PhoneType.class)
  private Map<PhoneType, Phone> phones;
  ...
}
 
@Entity
public class Phone {
  @Id
  private long id;
  ...
}
 
@Embeddable
public class PhoneType {
  @Basic
  private String type;
  ...
}

Example of a map key class embedded relationship XML

<entity name="Employee" class="org.acme.Employee" access="FIELD">
    <attributes>
        <id name="id"/>
        <one-to-many name="phones">
            <map-key-class>PhoneType</map-key-class>
        </one-to-many>
    </attributes>
</entity>
<entity name="Phone" class="org.acme.Phone" access="FIELD">
    <attributes>
        <id name="id"/>
        <many-to-one name="owner"/>
    </attributes>
</entity>
<embeddable name="PhoneType" class="org.acme.PhoneType" access="FIELD">
    <attributes>
        <basic name="type"/>
    </attributes>
</embeddable>

Copyright © Eclipse Foundation, Inc. All Rights Reserved.