Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

...

  • Java code: This tutorial comes with the following java source files:
    • index.jsp: This is the interface code only. It does call into other classes but it does not use any OpenJPA code directly.
    • InventoryEntityBroker.java: This class contains methods that encapsulate the OpenJPA handling code. It is provided as a way to separate OpenJPA functionality from the web interface.
    • InventoryItem.java: This is an OpenJPA Entity class file. This file is an example of a simple OpenJPA Entity with a relationship.
    • InventoryCategory.java: This is an OpenJPA Entity class file. This file is an example of a simple OpenJPA Entity with a relationship.
  • Persistence code: Each entity concept that would be a database table will be its own class. In this case, the tables are called "InventoryItem" and "InventoryCategory". Annotations in the Java file will associate the properties with the database columns. The annotation, @Column, maps the property name to the column name for synchronization with the database. If the table corresponding tables do not exist, OpenJPA can use these annotations to create the tables' schema dynamically based on the property type and length.

...

Info
titleNote

In this example, the property annotations ( @Column,@Version, and @Id) are placed on the getter methods. They can alternatively be placed on the property declarations. For more information on these annotations and to see what other annotations are in OpenJPA, see the Apache OpenJPA 2.0 User's Guide: Chapter 5

  • The annotated class and property declarations are all that are required.
  • The @Id annotation is needed as the unique identifier (primary key) for each record.
  • The @Version annotation is common practice. It ensures data integrity during merges and acts as an optimistic concurrency control.
  • Every property must have both a getter and a setter and the standard case convention must be observed.
              °  Correct: public void setCategoryName(String name)
              °  Incorrect: public void setcategoryname(String name)

...

  • Persistence.xml: JPA requires the use of a XML file called the "persistence.xml" that describes how to access the data. The XML file must be created in the META-INF directory. The META-INF directory containing the persistence.xml must be located with the source files.




    In the following example, the file only requires a few fields.

    Code Block
    xmlxml
    titleMETA-INF/persistence.xml
    borderStylesolid
    xml
    <persistence xmlns=http://java.sun.com/xml/ns/persistence
        xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
        version="1.0">
        <persistence-unit name="InventorySystem" transaction-type="RESOURCE_LOCAL">
            <class>tutorial.InventoryItem</class>
            <class>tutorial.InventoryCategory</class>
            <properties>
                <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
                <property name="openjpa.ConnectionURL" value="jdbc:derby://localhost:1527/StoreSystem"/>
                <property name="openjpa.ConnectionDriverName" value="org.apache.derby.jdbc.ClientDriver"/>
            </properties>
        </persistence-unit>
    </persistence>
    


  • The following elements are specific to this tutorial:
    • persistence-unit: the name is the table name to bind. In this case it is 'person'.
    • class: the java class that is bound to the table 'person'.
    • property: openjpa.jdbc.SynchronizeMappings: This tells OpenJPA to automatically create the table with the class definition if a table does not already exist.
    • property: openjpa.ConnectionURL: The URL of the database connection.
    • property: openjpa.ConnectionDriverName: the class name of the JDBC driver for Derby. This must be available via the classpath. In this tutorial, the driver is built into Geronimo so no extra actions are needed.
  • A complete explanation of the persistence.xml is in the Apache OpenJPAV2.0 user's Guide: Chapter 6

  • Create the Entity Manager. In the provided code, the EntityManager is a property of the InventoryEntityBroker class. The Entity Manager controls the interaction with the database. You must use the Entity Manager to start or access transactions or to send queries.
    • The following code must be added before using any of the persistence APIs (If you are using the provided sample code, this is already included):
      Code Block
      java
      java
      EntityManagerFactory factory = 	Persistence.createEntityManagerFactory("InventorySystem",
            System.getProperties());
      
      EntityManager em = factory.createEntityManager();
      
    • Note that the name, "InventorySystem", is the same one identified in the persistence.xml.
    • This code can be placed just before a query or transaction or they can be class properties.
    • Regardless of the scope, the EntityManager and the EntityManagerFactory should be closed when they are no longer needed:
      Code Block
      java
      java
      ...
      em.close();
      factory.close();
      ...
      
    • The EntityManagerFactory and EntityManager full descriptions are in the following OpenJPA documentation:
  • DB interface class. In this example, the InventoryEntityBroker class contains all the OpenJPA database interaction code. This is not required but it is a good idea for keeping the functionality componentized. For example, if you want to pull all of the records from the InventoryItem table, the code would look like this:
    java
    Code Block
    java
    titleInventoryEntityBroker.java
    java
    ...
    List<Person> getAllItems()
    {
         Query q = em.createQuery("SELECT item FROM InventoryItem item");
    
         return (List<InventoryItem>)q.getResultList();
    }
    ...
    
    java
    Code Block
    java
    titleindex.jsp
    java
    ...
    List<InventoryItem> itemList = getAllItems();
    ...
    
    • All of the specific APIs are described in the OpenJPA javadoc (http:/openjpa.apache.org/builds/latest/docs/javadoc/index.html)
    • Notice that the Query is not standard SQL. It is actually JPQL, which is a specialized form of query language specifically designed for JPA.
      • In the JPQL statement, "SELECT item FROM InventoryItem item", notice that InventoryItem has the same case as the class InventoryItem.
      • JPQL uses java objects in the query and not the database table names. The statement identifies the variable for InventoryItem as "item".
      • JPQL provides an object oriented query language that is independent of the database being queried.  So, regardless of which database being used, the JPQL does not change.  The JPA runtime takes care of doing the translation from the object world to the desired relational database.
      • For more information on JPQL, check out this Java Persistence Querly Language reference.

  • Also in the InventoryEntityBroker is code to add entries the database tables. Since you did not create a table for InventoryItem in the StoreSystem database in Derby, OpenJPA 2.0 will create the table the first time an "add" is attempted.
    • Consider the following code: java
      Code Block
      java
      titleInventoryEntityBroker
      java
      ...
      void addItem(String name, String description, float price, int categoryID)
      {
          InventoryItem item = new InventoryItem();
          item.setName(name);
          item.setDescription(description);
          ...
      
          em.persist(item);
      }
      ...
      
      You can then call the addItem() method in another part of the code. The EntityManager.persist() method will throw an exception if a transaction has not been started. The transaction must be committed by calling the Transaction.commit() method after all updates have been applied or else the changes will not be saved to the database:
      Code Block
      ...
      em.getTransaction().begin();
      
      addItem(...);
      
      em.getTransaction().commit();
      ...
      
      • When this is executed the first time it will use the annotations to create the Person table, then OpenJPA 2.0 will populate it with the provided data.
      • Note the use of the getTransaction() method to start an update and then to commit it. The concept is the same as in any database transaction processing.
      • Also note that while the getAllItems() function requires a JPQL SELECT query, the update type actions have APIs.
      • Take a look in the InventoryEntityBroker code at the addItem(), updateItem() and deleteItem() functions and note the simplicity of these operations.
  • An important aspect of relational databases is, of course, the relationships. The basic relationship types are: one to many, many to one, and many to many. OpenJPA provides annotations to identify the related fields.
    Open the source file, InventoryCategory.java in Eclipse and find the following code: java
    Code Block
    java
    titleInventoryCategory.java
    java
    ...
    @OneToMany(targetEntity=tutorial.InventoryItem.class,
       cascade=CascadeType.ALL,
       mappedBy="category")
    public List<InventoryItem> getItems()
    {
        return items;
    }
    ...
    
    • The annotation @OneToMany identifies that:
      • This object has a one-to-many relationship with targetEntity=tutorial.InventoryItem.class. Meaning that one InventoryCategory can have many InventoryItems associated with it.
      • The property of InventoryItem that specifies the InventoryCategory it is associated with is mappedBy="category". In other words, InventoryItem has a class property of type InventoryCategory named "category".
        Now open the source file, InventoryItem.java and find the following code: java
        Code Block
        java
        titleInventoryItem.java
        java
        ...
        @ManyToOne
        @JoinColumn(name="CAT_ID", nullable=false)
        public InventoryCategory getCategory()
        {
            return category;
        }
        ...
        
      • The annotation @ManyToOne identifies that:
      • This object has a many-to-one relationship with the InventoryCategory object. Meaning that there many InventoryItems can reference the same InventoryCategory
    • The annotation @JoinColumn identifies that:
      • The column in the database table that holds the InventoryCategory reference by the attribute: name="CAT_ID".
        Info
        titleRemember

        These annotations contribute to the creation of the tables and the relationships. It is important to put as much thought into how these objects relate to each other as you would if you were designing the database tables because you are designing the database tables.
        You can see more about the relationship annotations at the Apache OpenJPA site. The  documentation is here.

...