Jump to: navigation, search

EMF/Teneo/EclipseLink/Understanding JPA Mapping

Understanding JPA Mapping of EMF with Teneo EclipseLink

Enabling Teneo

EMF does not conform to the requirements for Entities defined in the JPA 1.0 specification. Coping with this mismatch is the principal focus of the runtime component of Teneo's EclipseLink JPA support. To enable Teneo's EMF support you must include the following property for each persistence unit in your persistence.xml:

<property name="eclipselink.session.customizer" value="org.eclipse.emf.teneo.eclipselink.EmfSessionCustomizer"/>

If you do not include this property Teneo will not be enabled and EclipseLink will fail to initialize your persistence unit and exit with an exception.

Naming Entities

EMF code generation produces interfaces and implementation ("impl") classes but JPA Entities must be impl classes. An Entity's name defaults to the short name of the class but this can lead to some awkwardness in JPQL queries. For example, the expanded Library example includes BookImpl and the interface Book.

public class BookImpl extends IdentifiableImpl implements Book {

With the default Entity name "BookImp" we would be required to use this name in JPQL. For example, "Select b from BookImpl b where b.title='Moby Dick'". The use of BookImpl in JPQL isn't very natural.

We can solve this by defining the Entity name of the BookImpl class to be Book.

    <entity name="Book" class="BookImpl" access="FIELD">
        ...

With this declaration we can write the query "Select b from Book b where b.title='Moby Dick'" which will return instances of BookImpl.

Mapping in XML vs. Annotations

If you are generating your mappings from Ecore an orm.xml file will be generated. If you are manually mapping then you should do all mapping in XML. The use of annotations is not recommended as they will be lost if/when you regenerate your model.

Field or Property Access

Regardless of what access type you specify, Teneo will adjust your mappings to use a hybrid access approach. To take advantage of lazy initialization, Teneo will configure property access when reading an attribute from a Enity. But to avoid firing events when constructing an object, Teneo wil configure direct field access when setting an attribute.

OneToMany

In JPA 1.0 OneToMany relationships require a 'back reference' from the target of the relationship (i.e., the objects in the collection) back to the owner of the relationship. The back reference should be mapped as a ManyToOne. The back reference mapping varies depending upon whether the many are contained.

OneToMany without EMF Containment

When dealing with a non-containment relationship, the target of the OneToMany mapping will need an attribute holding the back reference which is mapped with a ManyToOne. In the extended Library example, WriterImpl has a non-containment OneToMany relationship with BookImpl. Note that the mapped-by is "author", an attribute of BookImpl that is mapped as a ManyToOne back to WriterImpl.

WriterImpl's books mapping:

   <entity name="Writer" class="WriterImpl">
         ...
         <one-to-many name="books" mapped-by="author" target-entity="BookImpl">
          ...

BookImpl's author mapping:

    <entity name="Book" class="BookImpl" access="FIELD">
        ...
        <many-to-one name="author" target-entity="WriterImpl">
        ...

OneToMany with EMF Containment

In the case of an EMF containment relationship, the back reference to the owning object is maintained in the eContainer attribute. In the Library example, a LibraryImpl has an EList of WriterImpls which in JPA is mapped as a OneToMany. Because LibraryImpl->WriterImpl is a containment relationship, each WriterImpl's eContainer reference will point to it's owning LibraryImpl.

LibraryImpl's writers mapping:

    <entity name="Library" class="LibraryImpl">
        ...
	<one-to-many name="writers" target-entity="WriterImpl" mapped-by="eContainer">
        ...

WriterImpl's back reference to it's eContainer:

    <entity name="Writer" class="WriterImpl">
        ...
        <many-to-one name="eContainer" target-entity="LibraryImpl">
        ...