Using Anorm


Anorm is basically a data access layer to talk to the database we are using. In this blog, we will be using mysql as our database. Anorm is the default persistence provider in play framewok. Anorm uses plain sql to interact with the database and provides an API to parse and transform the resulting datasets.

To start with anorm, you need to include the following external dependncy of anorm in your build.sbt file :

libraryDependencies += “com.typesafe.play” %% “anorm” % “2.4.0”

Anorm requires a SQL schema creation / destruction script since it doesn’t do auto schema creation. Create a new file named “conf/evolutions/default/1.sql” containing:

# --- First database schema
# --- !Ups schema creation statements
CREATE TABLE table1 (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
# --- !Downs schema destruction statements
DROP TABLE IF EXISTS table1;

The steps we need to follow to be able to start using anorm are :

1. Define the data sources in the application. conf.

We can connect to the any databases, we have defined in the application.conf.
You can declare as many data sources as you want. By convention, the evolutions.default datasource is named `evolutions.default`

db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/test1?characterEncoding=UTF-8"

db.testdb.driver=com.mysql.jdbc.Driver
db.testdb.url="jdbc:mysql://localhost/test2?characterEncoding=UTF-8"

2. Connect to the database.

Import the DB object of play api.

import play.api.db._
DB.withConnection { implcit connection
//Here comes the queries to be excecuted
// Note : all sql statement needs database connection as an
// implicit paramter to be exectued
}

There are one of the several ways to connect to the databases.

We can connect to the default database, with transaction using DB.withTransaction

And If we need to connect to the specific database other than default, just pass the database name as the string parameter to the withConnection method.

For example,


// test1 is the name of the database
DB.withConnection("test1")
DB.withTransaction("test1")

3. Within the connection, we write the sql statement to be executed. Anorm gives us a way to write raw SQL and create a Scala object of type SqlQuery. SqlQuery has mehods to execute the query and return various types of result.

import play.api.db._
import anorm._

case class Test(id: Long, name: String)
val simple: RowParser[Test] = {
get[Long]("id") ~
get[String]("name")
map { case id ~ name ⇒ Test(id, name) }
}

// executes the select query and returns result mapped to Test case class
def getData(name : String)  : Test = {
DB.withConnection { implicit connection ⇒
SQL( """SELECT * from test1 where name = {name}""")
.on('name -> "Test data 1")
.as(simple.single)
}

// executes the insert statement and returns the number of rows effected
def insertData(name : String) : Int= {
DB.withConnection { implicit connection ⇒
SQL( """INSERT  into test1 values(1,'xyz')""")
.executeInsert
}

// executes the insert statement and returns the number of rows effected
def updateData(name : String) : Int = {
DB.withConnection { implicit connection ⇒
SQL("""UPDATE test1 set name = {name} where name = 'xyz'""")
.on('name -> "Test data 1").executeUpdate
}
}

Let’s have a brief explaination of the aforesaid method,

We can create the sql queries using the SQL string interpolator

SQL( """SELECT * from test1""")

If your SQL query needs dynamic parameters, you can declare placeholders like{name} in the query string, and later assign a value to them:

SQL( """SELECT * from test1 where name = {name}""").on('name -> "Test data 1")

We can get result from SQL query using RowParser which can be mapped to the single column or as a case class.

SQL( """SELECT name from test1 where name = {name}""").on('name -> "Test data 1").as(get[String]("name") single)
SQL( """SELECT name from test1 where name = {name}""").on('name -> "Test data 1").as(get[Option[String]]("name") singleOpt)
SQL( """SELECT name from test1 where name = {name}""").on('name -> "Test data 1").as(get[String]("name") *)

We can expect a single row to be retrieved as single, option of single or list of values.

For eg, we can define a parser get[String](“name”) to transform a single column result set row, to a a string, which in turn transformed into a ResultSetParser for a single row using single.

We can also map the row of the result to a single case class, and get the results in the same manner as above but expecting the rows to be fetched as single value object, optional value object or list of values objects.

In the simplest case, Anorm allows you to map the results of a query to a Scala case class like the following:

case class Test(id: Long, name: String)
val simple: RowParser[Test] = {
get[Long]("id") ~ // "id" is the int column name defined in the database
get[String]("name") // "name" is the string column name defined in the database
map { case id ~ name ⇒ Test(id, name) }
}

eg.

SQL( """SELECT * from test1 where name = {name}""").on('name -> "Test data 1").as(simple single)
SQL( """SELECT * from test1 where name = {name}""").on('name -> "Test data 1").as(simple singleOpt)
SQL( """SELECT * from test1 where name = {name}""").on('name -> "Test data 1").as(simple *)

That is all we need to know to start implement anorm.
We will have some details about handling the complex join results in the next part of the blog.
Thanks!

 

 

Advertisements
This entry was posted in Scala and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s