Showing posts with label JPA. Show all posts
Showing posts with label JPA. Show all posts

Tuesday, 19 May 2015

JPA Schema Generator

This is a sample of using the de.juplo plugin for generating a database schema from annotated JPA Entity classes.

The Config


 <plugin>
    <groupId>de.juplo</groupId>
    <artifactId>hibernate4-maven-plugin</artifactId>
    <version>1.1.0</version>
    <executions>
        <execution>
            <id>package</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>export</goal>
            </goals>
            <configuration>
                 <hibernateDialect>org.hibernate.dialect.MySQL5Dialect</hibernateDialect>
            </configuration>
        </execution>
        <execution>
            <id>test</id>
            <phase>process-test-resources</phase>
            <goals>
                <goal>export</goal>
            </goals>
            <configuration>
                <outputFile>${project.build.testOutputDirectory}/schema.sql</outputFile>
                <hibernateDialect>org.hibernate.dialect.H2Dialect</hibernateDialect>
            </configuration>
        </execution>
    </executions>
    <configuration>
        <target>SCRIPT</target>
    </configuration>
 </plugin>

Note that the normal configuration doesn't need an outputFile because it is generated in the target directory by default.  This example uses two executions, the first for the standard target build and the second for a test build for use with H2 for unit testing.
The <target>SCRIPT</target> part means that a sql script is created rather than trying to execute this directly on a database.

For more information see http://juplo.de/hibernate4-maven-plugin/

Wednesday, 13 August 2014

@Transactional

When connecting to a database a transaction is often required.  There are a number of ways of doing this but the most common is to use Spring transactions.

pom.xml

This dependency is needed to allow transactions

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<scope>compile</scope>
</dependency>


Spring Context

In the spring configuration an entity manager is necessary (see Entity Manager blog entry)

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

<!-- Define a transaction manager so that the @TransactionConfiguration and @Transactional can be used -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Proxy Class

The above combination will allow spring to create proxy classes which create a transaction before passing into the @Transactional method.  This means that because it is a proxy @Transactional doesn't work for any 'internal' call within the your class.  Eg even if a method is public if it is called from within the same class it won't pass through the proxy and therefore won't have a transaction.
If this type of behaviour is required then the transactions can be wired using AOP and the transaction code is created at compile time rather than a runtime proxy.

Exception Handling

Normal exceptions can be caught using the normal try - catch but if the database isn't there at all then there is an exception generated in the proxy before the method code is called.  The exception is a 
    org.springframework.transaction.CannotCreateTransactionException

To catch the exception within the same method as the actual database errors the transaction can be created a different way.

Programmatic Transactions

A programmatic transaction can be created using the TransactionTemplate in which case the TransactionException (CannotCreateTransactionException) can be caught in the same place.

    try
    {
        transactionTemplate.execute(new TransactionCallbackWithoutResult()
        {
            @Override
            protected void doInTransactionWithoutResult(final TransactionStatus status)
            {
                 // Do something to the database here
            }
        });
    }
    catch (PersistenceException | TransactionException e)
    {
        LOG.error("Database Error", e);
    }

There is also a TransactionCallback() which returns the object from the database whereas the one above doesn't do that.

The transactionTemplate can be created in spring configuration,

    <property name="transactionTemplate">
        <bean class="org.springframework.transaction.support.TransactionTemplate">
            <constructor-arg ref="transactionManager" />
</bean>
    </property>






Wednesday, 24 July 2013

JPA Entity Manager

Setting up an EntityManager for JPA can be done in a number of ways.  Below is a simple example to get something going.  It uses spring 3 and the packagesToScan option so that a persistence.xml file is not required.

persistence.xml

The persistence.xml file normally lives in the META-INF directory of src/main/java but if the packagesToScan option is going to be used in the EntityManagerFactory then this file should not be present at all.

DataSource

The DataSource defines the database that is used.  For simple development this can just be included as shown below however, two useful changes can be done.  Firstly, externalise the properties to a property file that can be changed without a recompile.  Secondly the datasource can be obtained by looking up a JNDI resource from the application server.

<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> 
<property name="url" value="jdbc:oracle:thin:@localhost:1521:XE" />
<property name="username" value="awhite" />
<property name="password" value="passw0rd" />
</bean>

Whichever driver is used needs to be on the classpath of the application.  In this case oracle.jdbc.driver.OracleDriver.

EntityManagerFactory

Creating an EntityManagerFactory is shown below.  The 'databasePlatform' will change depending on the database that is being connected to.  The 'hibernate.show_sql' and 'format_sql' are useful for debugging purposes but could be configured in a property file to allow them to be changed later.

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="packagesToScan" value="com.my.packages" />
        <property name="dataSource" ref="myDataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
                <property name="generateDdl" value="false" />
            </bean>
        </property>
        <property name="jpaProperties">
            <props>
                <!-- General settings -->
                <prop key="hibernate.archive.autodetection">class, hbm</prop>
                <prop key="hibernate.current_session_context_class">jta</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
            </props>
        </property>
    </bean>
 

PersistenceAnnotationPostProcessor

The PersistenceAnnotationPostProcessor is included so that the EntityManager created by the JPA implementation (eg Hibernate) can still be wired into classes with spring even though it isn't spring that creates and manages that class.

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
 
This bean allows the @PersistenceContext annotation to be included in classes and the developer can assume that the EntityManager will be there at runtime. Here is an example of the annotation.

    /** JPA entity manager. */
    @PersistenceContext
    private EntityManager entityManager;










Wednesday, 8 August 2012

JPA Notes


Here are a series of JPA notes that have been useful in the past.

EntityManager Methods

entityManager.persist() - creates a new object and saves it - will throw an EntityExistsException if it exists already - transaction is rolled back.

entityManager.merge() - will either save or update the current object as it is now!  Changes after this won't be saved.  See below - the merge creates a new object which is managed but the object which merge was called on isn't managed

entityManager.getReference() - gets a reference to the object assuming that it exists.  It does a look up against the @Id annotated field in the entity.  The reference will only exist for the duration of the transaction.  Hence get the data into a DTO before the transaction ends.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e);
e.setSomeField(someValue);
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue);
// tran ends but the row for someField is not updated in the database (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue);
// tran ends and the row for someField is updated (the changes were made to e2, not e)

JPA Callbacks

There are a number of callback methods in JPA which allow interaction at various points before and after the db save.  These are annotation driven and the names make it pretty clear when they are used.

@PrePersist

@PreUpdate

@PreRemove

@PostLoad

@PostPersist

@PostUpdate

@PostRemove


Annotations

JPA is usually annotation driven.  This provides the information locally to the class and is pretty tidy.  Here are some brief explanations about what the different annotations mean.

@Entity
Flags that an entity should be managed by JPA.  Note Entity exists in JPA and Hibernate so get the import statement right.

@Table
Defines the table that this entity maps to
    @Table(name = "MY_TABLE", schema = "MY_SCHEMA") 

@OneToMany
One of these classes links to many of another class

    @OneToMany(mappedBy = "<java_object_name>", targetEntity = <the_many_class.class>, cascade = CascadeType.ALL, fetch = FetchType.LAZY)

mappedBy shows that the other table is the 'owner' of the foreign key and a @ManyToOne would be expected on that table for a bi-direction relationship.  The mappedBy is only necessary for a bi-directional relationship.  The targetEntity is usually not required because the class variable that this annotation applies to will give this information. If there is only a uni-direction relationship then just a

    @OneToMany
    @JoinColumn(name="column_name")

@ManyToOne
The reverse of the annotation above.  This will allow a bidirection link from the many class back to the one class.
    @ManyToOne(targetEntity = <the_one_class.class>, fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "MY_COLUMN")

@ManyToMany
A join that uses a join table. Bi-directional is still possible using the mappedBy as above.  The owning class (Employee in this case) would have this code.

    @ManyToMany
    @JoinTable(name=EMPLOYEE_TO_PROJECT, joinColumns=@JoinColumn(name="EMPLOYEE_ID"), inverseJoinColumns=@JoinColumn(name="PROJECT_ID"))
    private List<ProjectEntity> projects;

The inverted side of this annotation (Project) would have the following,

    @ManyToMany(mappedBy = "projects")
    private List<EmployeeEntity> employees;

@OneToOne
A link between tables on a 1 : 1 basis.  For the table that has the column foreign key use

    @OneToOne
    @JoinColumn(name = "EMPLOYEE_ID")
    private Person person;

on the non-hosting table (ie without the join column) use

    @OneToOne(mappedBy = "person")
    private Employee employee;
 
@Embeddable
A set of 'columns' which can be in a reusable java class but exist in the underlying table.  Address might be an example of this.

@Embedded
An object which is used in this @Entity but is itself @Embeddable.

@MappedSuperClass
Allows class heirarchy in the Java and maps the contents of this class onto the table of the subclass.  EG map a column which exists on every table in a class annotated with @MappedSuperClass and then subclasses will 'inherit' this column into their table. There is still only one table though.  See @Inheritance for table inheritance. If all columns have an OBJECT_ID, CREATED_DATE then these could go in a class with the @MappedSuperClass and all classes could extend this.

@Inheritance
When a class with @Entity extends another class with @Entity then the @Inheritance rules can be set using this annotation.  The 'strategy' can be JOINED (there are two tables which are 'joined' using the sql request), SINGLE_TABLE (there is a single table a bit like Embedded) or TABLE_PER_CLASS (every table has a complete copy of all the data from the whole hierarchy but every table has that)

@OrderBy
Used on a list to order the elements directly out of the database.  The syntax is @OrderBy("<variable name> ASC").  The variable name is the variable in the objects which make up the list so for example List<Person> personList would have a variable from the Person class.

@PersistenceContext

Using the @PersistenceContext allows spring to wire in the JPA EntityManager to be used within the domain structure.

Create a BaseRepository that includes

    public class BaseRepository
    {

        @PersistenceContext
        private EntityManager entityManager;


        /**
         * Gets the entityManager value.
         * 
         * @return the entityManager
         */
        protected EntityManager getEntityManager()
        {
            return this.entityManager;
        }
    }


Spring will then populate this with the entity manager provided the spring configuration has the following line


    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


A getEntityManager() can be used in the SubClasses to get the entity manager instance.

Query Examples

Get a list of objects from a table,


    public List<MyEntity> getMyEntities()
    {
        final Query query = getEntityManager().createQuery("from MyEntity");
        return query.getResultList();
    }



Get a specific object using a primary key,


    final MyEntity myEntity = getEntityManager().find(MyEntity.class, id);



Use a query with parameters, where name is a provided value and type is an enumeration,


    final Query query = getEntityManager().createQuery("from MyEntity where name = :name and type = :type");
    query.setParameter("name", name);
    query.setParameter("type", MyEntityType.TYPE);
    return query.getResultList();


Creating a query that has a @OneToMany relationship needs a little bit more work.  Here the Company has a list of Products.  It is the products that need to be searched but the companies that need to be returned.  The SELECT only returns the CompanyEntity alias and because this is a @OneToMany the IN(c.products) is used.

    Query query = getEntityManager().createQuery("SELECT c FROM CompanyEntity AS c, IN(c.products) AS p WHERE p.name like :name");
    query.setParameter("name", name);
    return query.getResultList();