Skip to content
FaKod edited this page Sep 14, 2010 · 2 revisions

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.

Example:

class MyClass extends Something with SimpleEntityManagerFactory with ThreadLocalEntityManager {
 def getPersistenceUnitName = "mip"
}

Queries and Transactions

define query strings

A XML file collects all the used HQL statements.
Current Scala persistence implementations are trying to provide type safe SQL/HQL statements as classes and objects. I don’t think that this is the best way.

  • SQL/HQL syntax is quite complex. IMHO it will not be possible to rewrite the whole functionality (especially taking into account SQL enhancements like PostGIS or db vendor dialects)
  • I have learned that it can make sense to change a SQL/JPQL statement in production (add redundancy tables etc.)
  • Nevertheless, type safe SQL/JPQL parameter are important
  • JPA and JPA2.0 are widely adopted and used (field proven implementations) java standards

JPAExtension.xml example file

<filter>
  <!-- simple JPQL query with one parameter-->
  <query id="UserFromName" jpql="select u from User u where u.name like ?1"/>

  <!-- simple native SQL query with two parameter-->
  <query id="DistancePointFromTextToLocID" jpql="select distance(pointfromtext(?1),lp.geometry) from location_point as lp where lp.loc_id=?2"/>

  <!-- JPQL query with one parameter and filer class. Maps N to name -->
  <query id="FindObjectItemFromNameWithFilter" alias="oi" jpql="oi.nameTxt like :N">
    <filterClass class="com.jpaextension.test.NameFilter">
      <binding var="N" attribute="name"/>
    </filterClass>
  </query>

  <!-- JPQL query with relation fetch statements and query annotations -->
  <query id="fetchFilter" alias="c" annotation="myAnno1 myAnno2">
	<fetch property="owner"/>
	<fetch property="sparePart" joinType="left"/>
  </query>	
</filter>

Execute Query with Filter Class

The above defined 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.

val filter: NameFilter = newFilterInstance(QueryId("FindObjectItemFromNameWithFilter"))
filter.name = "%Test%"

var i = 0
forQueryResults {
  oi: ObjectItem =>
    i = i + 1
} withQuery (filter)
i must_== 10

fetch statement for preload relations

The fetch tag allows the preload of (lazy) relations. In case of fetchFilter the relations owner and sparePart are fetched while loading the data from DB.

annotations for the executed query

For the design of persistence layers it is useful to provide some query annotations (as a list of simple text). myAnno1 is an example. Annotations can be retrieved using a filer object.

Query Snippets

Sometimes several queries contain a common part. This can be put as a constant snippet to JPAExtension.xml.

example using a query with one expected result and no transaction

withNoTrx {
  val user: User = oneResultQuery withQuery (QueryId("UserFromName"), "Lionel")
  user
}

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 SQL query and expect one result

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

REST examples

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.

 @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)
         }
       }
     }
   }
 }

Filter Usage Examples

Defining Filter (query) Object and Query

The XML snippet defines that com.jpaextension.test.data.SomeFilter will contain the binding parameter NT and CID for query MyOIQuery.

<query id="MyOIQuery" alias="oi" jpql="oi.creatorId=:CID and oi.nameTxt=:NT">
    <filterClass class="com.jpaextension.test.data.SomeFilter">
        <binding var="CID" attribute="creatorId"/>
        <binding var="NT" attribute="nameTxt"/>
    </filterClass>
</query>

The following code creates a Filter Object myFilter, sets the binding parameter and executes the query.

withNoTrx {
	val myFilter: SomeFilter = newFilterInstance(QueryId("MyOIQuery"))

	myFilter.creatorId = BigInteger.valueOf(815)
	myFilter.nameTxt = "Test1"

	val result = createFilterQuery[ObjectItem](myFilter).getResultList
	result.size must_== 1
}