Annotating ActionScript Classes with Custom Metadata + Simple ORM Framework for AIR

A little known feature of Flex 3 is that you can annotate ActionScript classes with your own metadata. For example you could annotate a class as follows:

package
{
	[Bindable]
	[Table(name="contact")]
	public class Contact
	{
		[Id]
		[Column(name="contact_id")]
		public var contactId:int;

		[Column(name="first_name")]
		public var firstName:String;

		[Column(name="last_name")]
		public var lastName:String;
		public var address:String;
		public var city:String;
		public var state:String;
		public var zip:String;
		public var phone:String;
		public var email:String;
	}
}

In this example, [Bindable] is a standard Flex metadata annotation while Table, Id and Column are custom. The -keep-as3-metadata compiler flag allows you to instruct the compiler to keep your metadata in the generated SWF so that you can get to this information at runtime using the reflection API (describeType).

To set the compiler flag, right-click the AIR project name in FlexBuilder, select “Properties”, and “Flex Compiler”. For this example, I added -keep-as3-metadata+=Table,Id,Column to the “Additional compiler arguments”. Notice that it is important to use += and not =, otherwise standard metadata annotations (like [Bindable]) will not be available in the SWF.

Custom metadata annotations can be used for all sorts of interesting things . For my session at MAX this year, I used custom annotations to build a simple persistence framework for AIR.

Using this framework, you annotate your model classes to indicate the database table that should be used to persist instances of that class, the identity field in your class (which corresponds to the primary key of that table), and name mappings when the database column name is different from the class field name. That’s all you have to do to provide your AIR applications with automatic persistence to the embedded SQLite database. No SQL to write! The framework will even generate the table if it doesn’t already exists.

For example to add a new contact to your database, you’d simply do something like this:

var contact:Contact = new Contact();
contact.firstName = "Christophe";
contact.lastName = "Coenraets";
contact.email = "ccoenrae@adob.com";
entityManager.save(contact);

to modify the contact:

contact.firstName = “Chris”;
entityManager.save(contact);

to remove the contact:

entityManager.remove(contact);

You can provide the entityManager with instances of any annotated class and it will figure out how to persist the object (how to generate the appropriate SQL statements) based on your metadata annotations.

Disclaimer: This is a simplistic proof of concept and is by no means a production ready ORM solution. Some basic assumptions are made for simplicity. For example, I assume that all primary key are autoincremented integers.

You can download the sample application here. To test it, create an AIR project in FlexBuilder, copy the sample files in that project, and set the compiler options as described above.

Comments

26 Responses to “Annotating ActionScript Classes with Custom Metadata + Simple ORM Framework for AIR”

  1. shaun on October 3rd, 2007 7:47 am

    Nice. Thanks for the example code.
    After playing with AIR and the embedded SQL functionality I thought I’d have a go a writing a ORM for AIR. This(metadata information) is the missing piece of the puzzle for me. I was considering an alternative approach but i prefer this option.

  2. Tink on October 4th, 2007 4:14 am

    Adding the metadata references as compiler arguments could end up being quite a dirty process if you have a lot of metadata you want to keep and you only have that single line text input comtrol.

    Is there any plan for an option to keep all as opposed to listing them individually?

    keep-as3-metadata=ALL

  3. Gregory Pierce on October 5th, 2007 10:01 am

    Are you going to implement the rest of JPA (object graphs and such) or are you leaving this as an exercise for the reader? :)

  4. mloncaric on October 5th, 2007 1:07 pm

    omg. Thank you very much

  5. Pat Ryan on October 7th, 2007 8:37 pm

    I attended your session at Adobe Max in Chicago. It was one of the best sessions of the conference.
    When I returned home I started to create a simple application to show the synchronous API, asynchronous API and finally your EntityManager. I created the database outside of the EntityManager so it existed before running the EntityManager create sql.

    I noticed by running it this way the EntityManager did not populate data. It turned out to be an assumption in the typeObject method. In there you had:
    instance[item.field] = o[item.column];
    which assumed the column was upper cased which mine were not. But they would have been if I let the EntityManager create the table. The columns were the same case as the Object property that I was loading so the SQLStatement would populate the object from column name.

    I added the following and was able to get my sample application to work for synch DB, asyncDB as well as your EntityManager.

    instance[item.field] = o[item.field];
    if( instance[item.field] == null ) {
    instance[item.field] = o[item.column];
    }

    Conversely if I created the table with the EntityManager but if I used my syncAPI example it would not work because of the upperCased columns. So I also had to modify the loadMetadata method to not upperCase the column names.

    If you would like to see a test case I can send you my simple example.

    Do you have any thoughts or comments on these changes? If I have misunderstood its usage just let me know.

    Thanks again for a great session and a nice piece of work.

  6. NetCfmx on October 8th, 2007 2:46 am

    Hi Christophe,
    I attended the very last session that you presented at max this year. I liked your session very much it was actually my favorite this year. When i started using air to make something simple to begin with of course a contact manager was the most obvious choice. So when i ran into some bump i used your application as reference. But i am a problem with the relation in this line of code:
    “var identity:Object = map[c].identity;”
    now when i used it in my code it failed giving a null object yet the object passed to the function arguments was in fact as expected is there anyone who can explain this line within this function?

    private function createItem(o:Object, c:Class):void
    {
    var stmt:SQLStatement = map[c].insertStmt;
    var identity:Object = map[c].identity;
    var fields:ArrayCollection = map[c].fields;
    for (var i:int = 0; i<fields.length; i )
    {
    var field:String = fields.getItemAt(i).field;
    if (field != identity.field)
    {
    stmt.parameters[":" field] = o[field];
    }
    }
    stmt.execute();
    o[identity.field] = stmt.getResult().lastInsertRowID;
    }

    Thanks

  7. Pat Ryan on October 8th, 2007 6:51 am

    Will you be making your presentation from Adobe Max available for download.

    Thanks

  8. Pat Ryan on October 8th, 2007 6:53 am

    Hi NetCFmx
    If you make your code available I would take a look as I have time.

    Maybe you could try the new Adobe share beta. It has been a really easy way for me to share files.

    http://www.adobe.com/go/share

  9. NetCFmx on October 11th, 2007 6:12 pm

    Hi Pat,

    Thanks for taking the time to look at this i have opened an account so you can get the files they are based on the example that Christophe has posted in his contact manager. Of course i modified a few things to make sure i was able to understand the structure of the code. I am trying to leverage the usage of SQL lite and the relation with the annotation of objects. When i studied the function i could not understand what was going on in the line of code :
    “var identity:Object = map[c].identity;”

    I miss the relation between the “map[c]” and the property “.identity”.

    Anyways here is the link check it out when you can

    you can message me at wws*at*worldwidesmith*dot*com

    Thank you
    https://share.adobe.com/adc/document.do?docid=68809bd9-785e-11dc-b75f-151d3f6d9313

  10. NetCFmx on October 11th, 2007 6:15 pm

    Figures of course two files two links here is the missing link.

    https://share.adobe.com/adc/document.do?docid=6977581e-785e-11dc-b75f-151d3f6d9313

  11. Sönke Rohde » MAX Barcelona - Short Notes on October 17th, 2007 1:34 am

    [...] Reflexion API (describeType). Christophe has posted some code regarding the ORM approach on this blog. Now this is opens real new possibilities. Now let’s wait when Hibernate or ActiveRecord is [...]

  12. flex video on November 8th, 2007 9:06 am

    Great Job. I think I will use this technique as part of my flex proejct.

  13. Dan Zeitman on November 15th, 2007 8:11 am

    Great concept. FYI… Since the AIR BETA is a relentlessly moving target… I noted some changes in the AIR API that will need to be addressed in order for your sample to work.

    new SQLConnection(); now takes no args

    in EntityManager.as
    you will need to change line 242:

    _sqlConnection = new SQLConnection(TRUE);

    to

    _sqlConnection = new SQLConnection();

    and in the main.mxml file line 21
    change:

    _sqlConnection = new SQLConnection(TRUE);

    to

    _sqlConnection = new SQLConnection();

  14. Láďa on November 21st, 2007 6:56 am

    I have just started building my first AIR application and I was terrified that I have to go back to SQL again. After I had spent for almost two years with Rails and ActiveRecord I almost forgot that SQL exists :-)

    But actually I think that it will not take much long for some ORM project to appear.

  15. ICQManZ on November 28th, 2007 6:27 am

    Prodaiy ICQ za 12$ za vse.Ïðîäàþ ICQ 12$ çà âñå.
    274-693
    324-994
    564-567
    605-800
    695-769
    985-425
    132-335
    478-575
    Sviaz so mnoi ICQ 458411483. Ñâÿçü ñî ìíîé ICQ 458411483

  16. eregilkibly on December 3rd, 2007 1:37 am

    Ricerca Farmacie. Inserisci il tuo CAP o la localita che ti interessa. CAP o localita. Se vuoi restringere la ricerca inserisci anche l’indirizzo comprare viagra on line

  17. Salesbuilder Beta 3 (AIR file + Flex Source Code) : Christophe Coenraets on February 4th, 2008 12:14 pm

    [...] DAOs used in the previous version. I might move to the annotation-based ORM approach introduced here in a future version. Finally, the “lazy loading” strategy has been improved as well and [...]

  18. » air orm on February 23rd, 2008 7:45 am

    [...] have already been some moves in this direction, but something styled after Hibernate or ActiveRecord would be nice. Subscribe [...]

  19. Anonymous on March 24th, 2008 6:19 am

    Dirty Latina Maids Jennifer Luv…

    Dirty Latina Maids Jennifer Luv…

  20. Dan Zeitman on April 27th, 2008 10:58 am

    – UPDATE —

    Again what a great technique… I’m using it to map value objects from one to another…

    FYI — Final release of Flexbuilder 3.0 doesn’t support the option=value syntax!!!!

    Instead you must repeat the option = value:

    -keep-as3-metadata “Column”
    -keep-as3-metadata “ID”
    -keep-as3-metadata “Table”

  21. Anthony on June 24th, 2008 5:18 am

    Thanks for that I had no idea you could add your own Metadata tags to your actionscript files.

  22. online amerikansk roulette on July 20th, 2008 5:36 pm

    online amerikansk roulette…

    philosophizing Simons sub syntactical …

  23. Sönke Rohde » Open Source and Flex on August 7th, 2008 10:05 am

    [...] Chotin asked for feedback on suggested projects related to Flex. Personally I would love to see an ORM framework like suggested by Christophe Coenraets which works with [...]

  24. Jacob Wright on August 15th, 2008 4:49 pm

    I will be using your Simple ORM as an example of projects that use metadata in my 360 Flex presentation this next week. I hope you don’t mind.

    I am presenting on how to use metadata and Proxy to create better APIs and will site you as someone who has done this.

    [Tink]: With Flex Builder 3, if your SWC was compiled with the -keep-as3-metadata option, any project the SWC is used in don’t need to add it. It will be added automatically! Helps since the -keep-as3-metadata=ALL isn’t available.

  25. sohbet on August 22nd, 2008 6:26 am

    omg. Thank you very much

  26. chat on August 22nd, 2008 6:27 am

    Thank you very much

Leave a Reply