JPAExtension (JPA for Scala, ORM for Scala) should:

be fully JPA 2.0 compliant Persistence Layer and Object Relational Mapper (ORM) for Scala

perfectly replace the Java API with Scala Collections and other niceties

support Transaction Scope Wrappers with Scalas Functional Programming abilities

JPAExtension is hosted on Github

Related Artikel are:

What is JPA

The Java Persistence API is a POJO persistence API for object/relational mapping. It contains a full object/relational mapping specification supporting the use of Java language metadata annotations and/or XML descriptors to define the mapping between Java objects and a relational database. It supports a rich, SQL-like query language (which is a significant extension upon EJB QL) for both static and dynamic queries. It also supports the use of pluggable persistence providers.

(this is taken from here)

Advantages:

Pluggable Implementations

Widely used standard

Widely available experience

Supported by application server vendors

Three major JPA 2.0 implementations:

Entity Manager and Entity Manager Factory

The framework suports custom EntityManagerFactory implementations. To simplify usage two Traits can be used.

SimpleEntityManagerFactory provides a non JNDI environment EM factory. Method getPersistenceUnitName has to be implemented to provide the persistence unit name as defined in persistence.xml.

ThreadLocalEntityManager provides one Entity Manager instance per Thread.

Mixing in Traits:

class MyClass extends Something with SimpleEntityManagerFactory with ThreadLocalEntityManager { /* * using persistence unit called "mip" here */ def getPersistenceUnitName = "mip" . . . }

Queries

Query definitions are externalized to an xml file.

I have learned that it can make sense to change a SQL/JPQL statement in production (add redundancy tables or change the statements itself etc.)

the fetch tag allows to preload of (lazy) relations

queries can have named text annotations that can be retrieved at runtime

Sometimes several queries contain some common parts. They can be combined as snippets.

Allows the typesafe definition of JPQL/SQL query parameter holder objects, the filter objects

examples for JPAExtension.XML

simple JPQL query with one parameter:

simple native PostGIS SQL query with two parameter:

JPQL query with one parameter and filer class. Maps N to name:

JPQL query with relation fetch statements and query annotations:

Execute Query with Filter Class:

The query with the ID FindObjectItemFromNameWithFilter can use the filter NameFilter for holding the binding attribute name. name will be used to replace N.

Since the query can return more than one result forQueryResults can be used to iterate over the result-set.

Filter definition:

class NameFilter { var name: String = _ }

Using Filter and executing query:

. . . val filter: NameFilter = newFilterInstance(QueryId("FindObjectItemFromNameWithFilter")) filter.name = "%Test%" var i = 0 forQueryResults { oi: ObjectItem => i = i + 1 } withQuery (filter) i must_== 10 . . .

Transaction Scope Wrappers

Iterating over query results without transaction

withNoTrx { forQueryResults { u: User => userIDs.add(u.getId) userNames.add(u.getName) } withQuery (QueryId("UserFromName"), "%" + name + "%") }

Find one entity, remove it and commit the transaction

withTrxAndCommit { findAndApply(id ) { u:User => remove(u) } }

Execute a native PostGIS SQL query and expect one result

withTrxAndCommit { oneResultQueryAndApply { d: Double => eStatRet.setDistance(d) } withNativeQuery (QueryId("DistancePointFromTextToLocID"), postGISPoint, user.getUsersLocation.getId) }

Server Side Usage Example

These examples are using a JAX-RS standard implementation from SUN called Jersey.

exceptionWrapper and checkAccessRights are used to generate WebApplicationExceptions and to check the access rights based on HTTP-session credentials.

The code updates the UserInfo entity with merge and commits the transaction.

@PUT @Path("UserInfo/{uid}") def updateUserInfo(@PathParam("uid") uid: String, eui: EUserInfo): EUserInfo = { exceptionWrapper { checkAccessRights { withTrxAndCommit { findAndApply(id(uid) ) { u:User => val userInfoId = u.getUserInfo.getId val newUserInfo: UserInfo = eui.getUserInfo newUserInfo.setId(userInfoId) merge[UserInfo](newUserInfo) } } } } }