Learn more about ORM with EclipseLink
The writing of ORM storage in JAVA follows the Jakarta Persistence specification v.3.2 and is achieved with the EclipseLink framework (the other compatible implementation being Hibernate).
Read the source files in your favorite development environment. We favor using Eclipse. Before importing the projects into Eclipse, build them by executing the following command:
Starting with the readme.md file in the examples root directory, work your way through the readme.md files in the order of the examples:
- With the Junit tests.
- With JAVA clients.
When you have understood the examples (especially the one with the persistence.xml and orm.xml files), you are ready to write your own ORM persistence.
Verify first that you are able to answer the following questions:
-
What are the classes of the model to persist? In
Example 1, what are the annotations used in the model
classes.
The entity classes of the model are Family, Person, and Job.
Here is the list of annotations used in these classes: @Entity, @Id, @GeneratedValue, @ManyToOne, @OneToMany, @Transient. We do not expect that you become JPA/EclipseLink developers, but you can browse the documentation that is referenced in the readme.xml files.
Note that we let the database generate the identifiers: @GeneratedValue(strategy = GenerationType.TABLE). -
Do the classes in the model have a constructor? How are
instances created? Do these classes have
an invariants method to check validity range of
the attributes?
Objects are instantiated using default constructors. Then, accessors are used to set the attributes.
These classes do not contain any invariants. This is not the place to define constraints. From a persistence perspective, certain constraints may be added to the relational database schema. From an application perspective, an invariant method may be programmed to verify business rules (See the classes of the micro-project). -
In the JUnit unit test of Example 1, what are the objects
necessary to begin a transaction? For preparing your answer,
you can browse the Javadoc documentation of the classes and
the methods used.
Firstly, create an Entity Manager Factory, which is linked to a given persistence unit, which is described in the persistence.xml file. The properties of the persistence unit are specified in this XML file. A connection to the database server is opened. Note also that the database schema is generated as specified at the end of the JDBC URL property in the XML file: “;create=true”.
Secondly, create an Entity Manager using the previous factory.
Thirdly, get an entity transaction object from the entity manager to begin the transaction.
For those who are interested, refer to Figure 2-2 of Section Understanding Object-Relational Entity Architecture in the EclipseLink documentation. -
Still using Example 1, in the test’s
method setUp, try commenting out all the lines
containing the call to method persist. What
happens?
Next, uncomment only the first call to persist: at Line 37. Execute command mvn test and explain what happens?Firstly, when all the calls to persist are not executed, no object is added to the database.
Secondly, with only the first call to persist, EclipseLink complains saying that “During synchronization a new object was found through a relationship that was not marked cascade PERSIST”. This is the role of annotation @OneToMany on attribute Family::members. You can browse the logging messages displayed in the console to see the SQL instructions performed when the em.getTransaction().commit() instruction is performed: one instruction “INSERT INTO FAMILY” and the list of “INSERT INTO PERSON” instructions.
Conclusion: the calls to persist at Lines 41 and 42 are not necessary. -
In Example 1's JUnit test, explain the comments in test
method checkFamily at Lines 85 and 86.
In JUnit, there is no guarantee that test methods will be executed in the order in which they are written in the test class.
-
What is the difference between
the persistence.xml files in Example 1 and
Example 2?
What is the impact in the JUnit test class?In Example 1, the XML file specifies that the Derby database is embedded: EmbeddedDriver.
In Example 2, this is the ClientDriver that is used.
In Example 2, the Derby Network database must be instantiated and started. Implicitly, it says the embedded driver is automatically instantiated when reading the XML file in Example 1. -
In Example 3, how are configured the persistence unit
properties?
As mentionned in the XML files, the properties are set in the Java code, and more particularly, in method JpaTest::configureJPA. Then, the properties are passed to method createEntityManagerFactory to create the entity manager factory.
-
In the directory of Example 4, add the following shell
script to start the Derby Network Server: start_derby_database.sh.
Grant execution permission to the shell script file and execute it. You get an error and there is no process executing the database:Apache Derby is programmed in Java. The error message tells us that the Java command in the shell script was not able to find the “main” class to start the Network Server.$ ./start_derby_database.sh localhost 1621 Error: Could not find or load main class org.apache.derby.drda.NetworkServerControl
To solve this issue, we can execute a Maven plugin, namely maven-dependency-plugin, when building the project. Practically, in the pom.xml file, before the lines containing </plugins> and then </build>, add the following content (it specifies that building the Maven artefact must execute the plugin, which copies Maven dependencies, by default, in directory target/dependency):Re-build the project and check that you have installed the Jar archives of Derby. Then, start the Derby Network Server using the shell script:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.2.0</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> </execution> </executions> </plugin>$ mvn clean install $ ls target/dependency/ | grep derby derby-10.17.1.0.jar derbyclient-10.17.1.0.jar derbynet-10.17.1.0.jar derbyshared-10.17.1.0.jar derbytools-10.17.1.0.jar $ ./start_derby_database.sh localhost 1621 ... : Apache Derby Network Server - 10.17.1.0 - (1913217) started and ready to accept connections on port 1621 ... : Trace turned on for all sessions. $ ps aux | grep -i derby $ # get the PID of the process $ kill -9 PID # to remove the Derby Network Server