HowtoUsetheCairngormPersistenceLibrary

How to Use the Cairngorm Persistence Library

Introduction

The Persistence library eases the communication between an Adobe AIR application and an SQLite database. Both use different type systems (relational SQL versus object-oriented ActionScript). This Object Relational Mapping (ORM) library follows an iBATIS approach.

Summary

There are a large number of Object Relational Mapping (ORM) libraries available, some are opensource and others are commercial. There is generally two schools of thought though, which are typified in the Java-world by Hibernate and iBATIS .
Hibernate is very much driven from the OOPs perspective, where you start with a domain model and decorate it is with metadata. The role of the library is to read and write objects to the database, it generates the SQL for you and often generates schema from the object model. The advantages are you have a single source, your object model, and don't necessarily require any specialist database knowledge.

Alternatively, there is iBATIS. It drives from the database. You have a relational data model (often pre-existing), an object model and you want to map between the two. You still write SQL and the library supports the maintainability of the SQL and mapping too and from the SQL and your object model. The benefits of this approach are they allow you to use the "database as a database" and leverage the skills of a database specialist.

There is no right or wrong. Your choice may depend on personal preference, skills available within your team or scale of application.

The Cairngorm Persistence Library adopts the iBATIS approach. If you prefer Hibernate then there are Hibernate-like-ORM libraries for AIR. There is one from David Tucker and also one from Christophe Coenraets.

Getting Started

To use the Cairngorm Persistence Library the SQL is placed in a SQL map and the developer writes a Data Access Object (DAO). You can parametrize your SQL using indexed ('?') and named ('@' and ':') parameters. Although, indexed parameters are only supports for \<Select/> statements. For all other statement you must provide an Object and use named parameters.

The PersistenceClient Class is main entry point to the Persistence framework. Your DAO will use PersistenceClient to create an instance of ISqlSession , from which operations can be performed against the database. For each operation on your DAO you are recommended to create a new instance of ISqlSession as it maintains state. For example, if you are manually demarking the transactional boundary then the SqlSession maintains the batch. If you are only executing a single statement within a transaction then you may choose to create a single instance of ISqlSession.

The SQL is externalized to a SQL map. You are encouraged to use multiple SQL maps for maintainability. The recommendation is to scope SQL maps by functional area.

The sample application shows how to initialize the Persistence framework using Parsley. If you look at PersistenceContext.mxml it shows how the PersistenceClient is instantiated.

Grammar

The SQL maps support the following grammar:

  • \<Create/>
  • \<Delete/>
  • \<Insert/>
  • \<Select/>
  • \<Update/>

Statements

The first time a statement is executed it is cached in the StatementCache for use in future operations. We do this because a statement must be prepared (compiled) before it can be executed. Once a statement has been prepared it doesn't need to be prepared again.

Metadata

All the metadata associated with the SQL is defined on the object. For example:

Person.as

package com.adobe.cairngorm.persistence.sample.domain
{

    [Bindable]
    public class Person
    {
        [Id]
        [Mapped]
        public var personId:int;

        [Mapped]
        public var firstName:String;

        [Mapped]
        public var lastName:String;

        [Mapped(typeHandler="dateTypeHandler")]
        public var dateOfBirth:Date;

        [Mapped(typeHandler="booleanTypeHandler")]
        public var friend:Boolean;

        [Association]
        public var address:Address;
    }
}

As can be seen from the above example there are three metadata tags, which are described in the following table.

Metadata Description Attribute
[Id] Used to specify the unique-id of an item. When you insert a new item the returned rowId is set on the id-property. Please refer to the following pages of the SQLite documentation: ROWIDs and Autoincrement
[Mapped] Specifies a mapped property By default is assumes the SQL parameter is called the same as the property. It also assumes the COLUMN name (for a \<Select/> statement is the same as the property, but in uppercase.
[Mapped(typeHandler="booleanTypeHandler")] - specifies a type handler, this is bidirectional.
[Mapped(parameter="name")] - allows you to override the SQL parameter name.
[Mapped(column="FIRSTNAME")] - allows you to override the COLUMN name.
[Association] Defines a 1:1 association. The Persistence Library will follow associations. For example, if you are selecting from a PERSON table and an ADDRESS table it will construct a Person Object with an association to an Address Object. If you are inserting a new Address you can simply pass the Person Object, it will then get what it needs to the Address and use the id of the Person for the foreign-key constraint.

Type Handlers

If you need to translate the value coming back from the database you can use a type handler. The metadata show how to specify the type handler, but it must be declared on the SQL map as in the following example.

<type:DateTypeHandler id="dateTypeHandler" />
<type:BooleanTypeHandler id="booleanTypeHandler" />

The following type handlers are included in the Persistence distribution:

  • DateTypeHandler
  • BooleanTypeHandler

If you want to provide your own type handler you can implement the ITypeHandler interface.

Transactions

When you execute an operation against the database an implicit transaction is created if one is not already in progress, this is done by the AIR SDK. If you explicitly call SqlSession.beginTransaction() a new transaction is started and all operations are batched. When you call SqlSession.commitTransaction() the batch of operations is executed sequentially. If there is an error executing one of the operations then rollback is called and no further operations in the batch are executed.

Database Access

The database can be accessed synchronously or asynchronously. As a general rule all writes are executed synchronously and all reads and batched operations are executed asynchronously.

You can override this behavior by calling SqlSession.accessDatabaseAsynchronously() or SqlSession.accessDatabaseSynchronously(). For example, a call to SqlSession.accessDatabaseAsynchronously() will execute all subsequent operations asynchronously. If you want to revert to the default mode then call SqlSession.useDefaultDatabaseAccess().

Sample

Take a look at the PersistenceTest for a reference implementation.

### Cairngorm 3 - [ Home ][1] - [ Guidelines ][3] - [ Tools ][4] - [ Libraries Downloads ][2]
### Cairngorm 2 - [ Home ][5] - [ Framework Downloads ][6] - [ Eclipse Plugin ][7]
### Project - [ Source ][8] - [ Bug Database ][9] - [ Submitting a Patch ][10] - [ Developer Documentation ][11] - [ Forums ][12] - [ License ][13]