Accessing MongoDB using JPA

In this recipe, we will use a JPA provider that allows us to use JPA entities to achieve object-to-document mapping with MongoDB.

Getting ready

Start the standalone server instance listening to port 27017. This is a Java project using JPA. Familiarity with JPA and its annotations is expected, though what we will be looking at is fairly basic. Refer to the Connecting to the single node using a Java client recipe in Chapter 1, Installing and Starting the Server, to see how to set up maven if you are not aware of it. Download the DataNucleusMongoJPA project from the bundle provided with this book. Though we will be executing the test cases from the command prompt, you can import the project to your favorite IDE to view the source code.

How to do it…

  1. Go to the root directory of the DataNucleusMongoJPA project and execute the following in the shell:
    $ mvn clean test
    
  2. This should download the necessary artifacts needed to build and run the project and execute the test cases successfully.
  3. Once the test cases get executed, open a mongo shell and connect to the local instance.
  4. Execute the following query in the shell:
    > use test
    > db.personJPA.find().pretty()
    

How it works…

First, let's look at a sample document that was created in the personJPA collection:

{
        "_id" : NumberLong(2),
        "residentialAddress" : {
                "residentialAddress_zipCode" : "400101",
                "residentialAddress_state" : "Maharashtra",
                "residentialAddress_country" : "India",
                "residentialAddress_city" : "Mumbai",
                "residentialAddress_addressLineOne" : "20, Central street"
        },
        "lastName" : "Sharma",
        "gender" : "Male",
        "firstName" : "Amit",
        "age" : 25
}

The steps that we executed are pretty simple; let's look at the classes that are used one by one. We start with the com.packtpub.mongo.cookbook.domain.Person class. On the top of the class (after the package and imports), we have the following:

@Entity
@Table(name="personJPA")
public class Person {

This denotes that the Person class is an entity and the collection to which it would persist is personJPA. Note that JPA was designed primarily as an Object Relational Mapping (ORM) tool and, so, the terminologies used are more for a relational database. A table in RDBMS is synonymous to a collection in MongoDB. The rest of the class contains the attributes of person and the columns annotated with @Column and @Id for a primary key. These are simple JPA annotations. What is interesting to look at is the com.packtpub.mongo.cookbook.domain.ResidentialAddress class, which is stored as a residentialAddress variable in the Person class. If we look at the person document that we gave earlier, all the values given in the @Column annotation are the names of the keys for person; also notice how Enum gets converted to a string value as well. The residentialAddress field is the name of the variable in the Person class against which the address instance is stored. If we look at the ResidentialAddress class, we can see the @Embeddable annotation at the top above the class name. This is again a JPA annotation that denotes that this instance is not an entity itself, but is embedded in another Entity or Embeddable class. Note the names of the fields in the document; in this case, they have the following format: <name of the variable in person class>_<value of the variable name in ResidentialAddress class>.

There is one problem here. The names of the fields are too long, consuming unnecessary space. The solution is to have a shorter value in the @Column annotation. For instance, the @Column(name="ln") annotation instead of @Column(name="lastName"), will create the key with a ln name in the document. Unfortunately, this doesn't work with the embedded ResidentialAddress class; in which case, you will have to deal with shorter variable names. Now that we have seen the entity classes, let's see persistence.xml:

<persistence-unit name="DataNucleusMongo">
  <class>com.packtpub.mongo.cookbook.domain.Person</class>
  <properties>
    <property name="javax.persistence.jdbc.url" value="mongodb:localhost:27017/test"/>
  </properties>
</persistence-unit>

We have got just the persistence-unit definition here with the name as DataNucleusMongo. There is one class node that is the entity that we will use. Note that the embedded address class is not mentioned here as it is not an independent entity. In the properties, we mentioned the URL of the data store to connect to. In this case, we connect to the instance on localhost, port 27017, and database test.

Now, let's look at the class that queries and inserts the data. This is our com.packtpub.mongo.cookbook.DataNucleusJPATest test class. We create javax.persistence.EntityManagerFactory as Persistence.createEntityManagerFactory("DataNucleusMongo"). This is a thread-safe class and its instance is shared across threads; the string argument is also the same as the name of the persistence unit that we used in persistence.xml. All the other invocations on javax.persistence.EntityManager to persist or query the collection require us to create an instance using EntityManagerFactory—use it and then close it once the operation is completed. All the operations performed are as per the JPA specifications. The test case class persists entities and also queries them.

Finally, we look at pom.xml, particularly the enhancer plugin that we used, which is as follows:

<plugin>
  <groupId>org.datanucleus</groupId>
  <artifactId>datanucleus-maven-plugin</artifactId>
  <version>4.0.0-release</version>
  <configuration>
    <log4jConfiguration>${basedir}/src/main/resources/log4j.properties</log4jConfiguration>
    <verbose>true</verbose>
  </configuration>
  <executions>
    <execution>
      <phase>process-classes</phase>
      <goals>
        <goal>enhance</goal>
      </goals>
    </execution>
  </executions>
</plugin>

The entities that we have written need to be enhanced in order to be used as JPA entities using data nucleus. The preceding plugin will be attached to the process-class phase and then call the plugin's enhance.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset