Stefan Horochovec

Blog sobre tecnologias que mudam a vida dos usuários

FlexORM – Framework ORM para persistência em AIR 1.5

with 13 comments

Olá pessoal,

Neste artigo, irei comentar um pouco sobre o FlexORM. Este framework tem como objetivo o mapeamento objeto-relacional em projetos que utilizem AIR e base de dados embarcada (SQLite).

O FlexORM é uma criação de Mark Moloney, e é hospedado pela RIAForge.

O FlexORM tem suporte a versão 1.5 do AIR e abaixo, podemos listar algumas de suas vantagens para seu uso:

* Não há necessidade de criação e atualização de tabelas. O FlexORM se encarrega da criação da estrutura do banco, através de um mapeamento feito dentro do próprio objeto a ser persistido;

* Possui suporte as operações CRUD;

* Suporta associações 1:N, N:M, N:1 e 1:1;

* Suporte a atributos transientes;

* Suporte a constraints para consistência de chaves-estrangeiras, através de triggers do SQLite;

* Transações;

* Criação automática de índices;

* Lazy Loading;

* Dentre outras;

Para exemplificar o uso do FlexORM, irei criar um projeto chamado DuckToDo e o objetivo do projeto é que eu possa cadastrar algumas tarefas que eu precise realizar. A aplicação é bem simples no quesito visual, uma vez que o intuito do artigo é o conhecimento do FlexORM.

Para iniciar, iremos criar um projeto no FlexBuilder chamado DuckToDo, conforme a tela abaixo:

Em seguida, vá as propriedades do projeto, e na opção Flex Compiler, adicione a seguinte linha de comando ” -keep-as3-metadata+=Table,Id,Column,ManyToOne,OneToMany,ManyToMany,Transient”, para que o compilador interprete as Metadatas adicionadas ao mapeamento dos Beans, conforme tela abaixo:

Feito isso, você deve fazer o download do FlexORM e adicionar ao seu projeto. Você pode optar por fazer o download do source através de um servidor de versionamento (subversion), ou fazer o download através deste link do arquivo .SWC do projeto FlexORM.

Depois de obter o .SWC, ou por download, ou recompilando o projeto, você deve adicioná-lo a pasta lib/ de seu projeto.

Feito isso, criaremos nossa classe de objeto que será persistida pela nossa aplicação.

Crie uma nova classe actionscript na package “org.flexduck.model” chamada Todo, e adicione o código abaixo:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.flexduck.model
{
 
	[Bindable]
	[Table(name="TODO")]
	public class Todo
	{
		[Id]
		public var codigo 	: int;
 
		[Column(name="titulo")]
		public var titulo 	: String;
 
		[Column(name="descricao")]
		public var descricao : String;
 
	}
 
}

Neste momento, quem trabalha com Java e utiliza Hibernate ou JPA já percebe uma grande semelhança. Através da Metadata [Table] no escopo da classe, definimos a qual tabela este objeto deve ser persistido.

No atributo codigo, foi adicionado a Metadata [Id] indicando que esse atributo corresponde a chave primária, ou o identificador, do objeto.

E nos atributos, titulo e descrição, adicionado a Metadata [Column] indicando que refere-se a uma coluna. Junto a Metadata também foi adicionado o nome respectivo da coluna na tabela.

Com isso, nosso bean está pronto para ser persistido. Vamos para a sua gravação.

Dentro do arquivo DuckToDo.mxml foi criada a seguinte estrutura de componentes.

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<mx:Binding destination="todo.titulo" 		source="titulo.text"/>
<mx:Binding destination="todo.descricao" 	source="descricao.text"/>
 
<mx:Panel width="500" height="250" layout="absolute" title="O que tenho para fazer?" horizontalCenter="0" verticalCenter="0">
 
<mx:ViewStack id="vw" top="0" right="0" left="0" bottom="0">
	<mx:Canvas label="Grid" width="100%" height="100%">
 
		<mx:Label x="10" y="10" text="Título" fontWeight="bold"/>
		<mx:TextInput x="10" y="29" width="460" id="titulo" text="{this.todo.titulo}"/>
 
		<mx:Label x="10" y="58" text="Descrição" fontWeight="bold"/>
		<mx:TextArea x="10" y="75" width="460" height="85" id="descricao" text="{this.todo.descricao}"/>
 
		<mx:Button x="318" y="172" label="Adicionar" id="btnAdd" click="btnAddHandler(event);"/>
		<mx:Button x="252" y="172" label="Listar" id="btnListar" click="btnListarHandler(event);"/>
		<mx:Button x="189" y="172" label="Novo" id="btnNovo" click="btnNovoHandler(event);"/>
		<mx:Button x="406" y="172" label="Excluir" id="btnDel" click="btnDelHandler(event);"/>
 
	</mx:Canvas>
 
	<mx:Canvas label="Formulario" width="100%" height="100%">
		<mx:DataGrid 	top="5" right="5" left="5" bottom="30" 
						id="dg" 
						doubleClickEnabled="true" 
						doubleClick="doubleClickHandler(event);">
			<mx:columns>
				<mx:DataGridColumn dataField="titulo"/>
			</mx:columns>
		</mx:DataGrid>
		<mx:Button label="Pesquisar" id="btnPesquisar" click="btnPesquisarHandler(event);" bottom="5" right="5"/>
		<mx:Button label="Cadastrar" id="btnCadastrar" click="btnCadastrarHandler(event);" bottom="5" right="90"/>
	</mx:Canvas>
 
</mx:ViewStack>
 
</mx:Panel>

Essa estrutura corresponde a um Panel, contendo um ViewStack com dois Canvas dentro. Para o primeiro Canvas foi adicionado um Grid para conter a lista de tarefas e no segundo Canvas, um pequeno formulário para a manutenção dos registros.

Nesse artigo não irei comentar sobre a estrutura do formulário, considerando apenas como relevante as instruções de uso do FlexORM.

Foi adicionado um evento no creationComplete da minha aplicação, para instanciar o banco de dados, conforme declaração abaixo:

?View Code ACTIONSCRIPT3
1
2
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
						creationComplete="initApp(event);">

E dentro do bloco de programação em ActionScript foi adicionado:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<mx:Script>
<![CDATA[
 
import org.flexduck.model.Todo;
import nz.co.codec.flexorm.EntityManager;
 
/**
 * Objeto de persistencia
 */ 
private var genericDAO 	: EntityManager	= EntityManager.instance;
 
/**
 * Classe para listar
 */
private var todoClass	: Class			= Todo;
 
/**
 * Bean
 */
[Bindable]
private var todo		: Todo			= new Todo();
 
/**
 * Evento disparado no creationComplete da aplicação para fazer a conexão com o banco de dados
 */
private function initApp(event:Event) : void
{
	var appDataBase : File = File.documentsDirectory.resolvePath("ducktodo.db");
	var sqlConn		: SQLConnection	= new SQLConnection();
	sqlConn.open(appDataBase);
	this.genericDAO.sqlConnection	= sqlConn;
}
 
/**
 * Função disparada no click do botão de "Adicionar"
 */
private function btnAddHandler(event:MouseEvent) : void
{
	this.genericDAO.save(this.todo);
	this.dg.dataProvider	= this.genericDAO.findAll(this.todoClass);
}
 
/**
 * Função disparada no click do botão de "Excluir"
 */
private function btnDelHandler(event:MouseEvent) : void
{
	this.genericDAO.remove(this.todo);
	this.dg.dataProvider	= this.genericDAO.findAll(this.todoClass);
}
 
/**
 * Função disparada no duplo click no grid de pesquisa
 */
private function doubleClickHandler(event:MouseEvent) : void 
{
	this.todo	= this.dg.selectedItem as Todo;
	this.vw.selectedIndex	= 0;
}
 
/**
 * Função disparada no click do botão de "Pesquisar"
 */
private function btnPesquisarHandler(event:MouseEvent) : void
{
	this.dg.dataProvider	= this.genericDAO.findAll(this.todoClass);
}
 
/**
 * Função disparada no click do botão de "Cadastrar"
 */
private function btnCadastrarHandler(event:MouseEvent) : void
{
	this.vw.selectedIndex 	= 0;
}
 
/**
 * Função disparada no click do botão de "Listar"
 */
private function btnListarHandler(event:MouseEvent) : void
{
	this.vw.selectedIndex	= 1;
}
 
/**
 * Função disparada no click do botão de "Novo"
 */
private function btnNovoHandler(event:MouseEvent) : void
{
	this.todo	= new Todo();
}
]]>
</mx:Script>

Alguns comentários relevantes:

Na função initApp, foi criado uma conexão SQLConnection, e a mesma foi passada para um objeto chamado genericDAO. Este objeto é uma instancia da classe EntityManager do FlexORM, responsável por executar os métodos para manipulação do banco de dados.

Na função btnAddHandler foi feita a persistencia do objeto Todo. Perceba que essa função é responsável por gravar e atualizar o objeto, não sendo necessário que o desenvolvedor se preocupe com a operação específica, apenas que em determinado momento, o objeto deve ser persistido, gravando-o ou fazendo sua atualização.

Na função btnDelHandler foi solicitado que determinado objeto fosse apagado do banco de dados.

Na função btnPesquisarHandler foi solicitado uma busca em todos os registros de determinada Classe, e não um objeto, fique atento a essa situação.

Os demais eventos servem para a navegação da tela, portanto, não serão comentados.

Se você fez corretamente a inclusão de todos os fontes, terá o resultado:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
						creationComplete="initApp(event);">
 
<mx:Script>
<![CDATA[
 
import org.flexduck.model.Todo;
import nz.co.codec.flexorm.EntityManager;
 
/**
 * Objeto de persistencia
 */ 
private var genericDAO 	: EntityManager	= EntityManager.instance;
 
/**
 * Classe para listar
 */
private var todoClass	: Class			= Todo;
 
/**
 * Bean
 */
[Bindable]
private var todo		: Todo			= new Todo();
 
/**
 * Evento disparado no creationComplete da aplicação para fazer a conexão com o banco de dados
 */
private function initApp(event:Event) : void
{
	var appDataBase : File = File.documentsDirectory.resolvePath("ducktodo.db");
	var sqlConn		: SQLConnection	= new SQLConnection();
	sqlConn.open(appDataBase);
	this.genericDAO.sqlConnection	= sqlConn;
}
 
/**
 * Função disparada no click do botão de "Adicionar"
 */
private function btnAddHandler(event:MouseEvent) : void
{
	this.genericDAO.save(this.todo);
	this.dg.dataProvider	= this.genericDAO.findAll(this.todoClass);
}
 
/**
 * Função disparada no click do botão de "Excluir"
 */
private function btnDelHandler(event:MouseEvent) : void
{
	this.genericDAO.remove(this.todo);
	this.dg.dataProvider	= this.genericDAO.findAll(this.todoClass);
}
 
/**
 * Função disparada no duplo click no grid de pesquisa
 */
private function doubleClickHandler(event:MouseEvent) : void 
{
	this.todo	= this.dg.selectedItem as Todo;
	this.vw.selectedIndex	= 0;
}
 
/**
 * Função disparada no click do botão de "Pesquisar"
 */
private function btnPesquisarHandler(event:MouseEvent) : void
{
	this.dg.dataProvider	= this.genericDAO.findAll(this.todoClass);
}
 
/**
 * Função disparada no click do botão de "Cadastrar"
 */
private function btnCadastrarHandler(event:MouseEvent) : void
{
	this.vw.selectedIndex 	= 0;
}
 
/**
 * Função disparada no click do botão de "Listar"
 */
private function btnListarHandler(event:MouseEvent) : void
{
	this.vw.selectedIndex	= 1;
}
 
/**
 * Função disparada no click do botão de "Novo"
 */
private function btnNovoHandler(event:MouseEvent) : void
{
	this.todo	= new Todo();
}
]]>
</mx:Script>
 
<mx:Binding destination="todo.titulo" 		source="titulo.text"/>
<mx:Binding destination="todo.descricao" 	source="descricao.text"/>
 
<mx:Panel width="500" height="250" layout="absolute" title="O que tenho para fazer?" horizontalCenter="0" verticalCenter="0">
 
<mx:ViewStack id="vw" top="0" right="0" left="0" bottom="0">
	<mx:Canvas label="Grid" width="100%" height="100%">
 
		<mx:Label x="10" y="10" text="Título" fontWeight="bold"/>
		<mx:TextInput x="10" y="29" width="460" id="titulo" text="{this.todo.titulo}"/>
 
		<mx:Label x="10" y="58" text="Descrição" fontWeight="bold"/>
		<mx:TextArea x="10" y="75" width="460" height="85" id="descricao" text="{this.todo.descricao}"/>
 
		<mx:Button x="318" y="172" label="Adicionar" id="btnAdd" click="btnAddHandler(event);"/>
		<mx:Button x="252" y="172" label="Listar" id="btnListar" click="btnListarHandler(event);"/>
		<mx:Button x="189" y="172" label="Novo" id="btnNovo" click="btnNovoHandler(event);"/>
		<mx:Button x="406" y="172" label="Excluir" id="btnDel" click="btnDelHandler(event);"/>
 
	</mx:Canvas>
 
	<mx:Canvas label="Formulario" width="100%" height="100%">
		<mx:DataGrid 	top="5" right="5" left="5" bottom="30" 
						id="dg" 
						doubleClickEnabled="true" 
						doubleClick="doubleClickHandler(event);">
			<mx:columns>
				<mx:DataGridColumn dataField="titulo"/>
			</mx:columns>
		</mx:DataGrid>
		<mx:Button label="Pesquisar" id="btnPesquisar" click="btnPesquisarHandler(event);" bottom="5" right="5"/>
		<mx:Button label="Cadastrar" id="btnCadastrar" click="btnCadastrarHandler(event);" bottom="5" right="90"/>
	</mx:Canvas>
 
</mx:ViewStack>
 
</mx:Panel>
 
</mx:WindowedApplication>

Basta exportar sua aplicação, e tudo deverá funcionar perfeitamente.

Forte abraço e até a próxima!

Written by Stefan Horochovec

janeiro 27th, 2010 at 12:08 am

Posted in AIR

Tagged with , ,

13 Responses to 'FlexORM – Framework ORM para persistência em AIR 1.5'

Subscribe to comments with RSS or TrackBack to 'FlexORM – Framework ORM para persistência em AIR 1.5'.

  1. Boa noite Stefan

    Excelente artigo! Eu havia feitos alguns testes no FlexORM e realmente ele é fantástico, muito similar ao JPA.
    Gostaria muito que a Adobe fizesse algo similar ao Hibernate no Air, com a possibilidade de conexão para vários banco de dados, não só ao SqlLite.
    Mas estou feliz como Air 2.0!!! rsrs.

    Grande Abraço, e parabéns pelo Blog.

    Robson Fernandes

    Robson Fernandes

    27 jan 10 at 1:02

  2. Muito bom o seu artigo, só uma opinião de leitor, tente colocar ao final da página um print de como vai ficar o projeto finalizado.

    vlw

    Jonathan C.

    27 jan 10 at 7:11

  3. @Robson Fernandes
    Isso seria fantástico, também gostaria de novas versões de bancos com suporte.

    Com relação ao AIR 2.0 é só aguardar que a próxima release será muito boa e já está chegando :D

    Obrigado por prestigiar o blog ;)

    Stefan Horochovec

    27 jan 10 at 8:30

  4. @Jonathan C.
    Obrigado por prestigiar o blog e também pela dica, vou colocar alguns printscreens do projeto e também vou disponibilizá-lo para download a noite.

    Stefan Horochovec

    27 jan 10 at 8:33

  5. E isso ae Stefan muito bom o artigo. Parabéns!

    Carlos Lima

    27 jan 10 at 8:37

  6. @Carlos Lima
    Obrigado por visitar o blog

    Stefan Horochovec

    27 jan 10 at 9:07

  7. Muito Obrigado pelo artigo Stefan… muito útil ;) é muito bom ver esses recurso dos Metadatas ser utilizados com mais frequencia nos frameworks para AS3, além disso um ORM é indispensavel hoje em dia, injeção de sql é um poerre, cada vez mais me sinto no ActionScript3 como se estivesse no java…hehe

    Cumps.

    jandersonfc

    27 jan 10 at 9:45

  8. @jandersonfc
    Valeu Janderson, e obrigado pela visita!

    Stefan Horochovec

    27 jan 10 at 11:04

  9. Tenho as seguintes classes:
    - Cidade (id, nome)
    - Cliente (id, cidade_id, empresa, email)

    Gostaria de saber como constrói a classe Cliente recebendo o nome da cidade.
    Tem como me passar um exemplo??

    Ricardo

    14 abr 10 at 20:06

  10. Bah tche…
    Parabéns pelo post.
    Simples e direto… não conhecia o FlexORM, gostei pela praticidade =)

    Abraços e até mais

    GuiSjlender

    Guilherme Sjlender

    7 mai 10 at 8:58

  11. @Guilherme, Valeu! Obrigado por visitar o blog e comentá-lo!

    Stefan Horochovec

    8 mai 10 at 18:24

  12. Parabéns Stefan

    Gostei muito do que vi no seu projeto parece simples, como sou iniciante gostaria de saber se tivesse um banco ja pronto com as tabelas, no lugar do “duck” o meu “banco” daria certo.? O processo crud continua o mesmo? e no flash 4 teria compatibilidade?

    agradeço qq informação.

    Octacilio

    Octacilio Nazaré

    14 jul 10 at 10:15

  13. Stefan muito bom esse teu artigo.
    Trabalho com java e uso hibernate.
    A semelhança é muito grande.
    Esse framework é uma mão na roda.
    Vlw.

    @adronilson

    10 jul 11 at 0:39

Leave a Reply

More in AIR (4 of 16 articles)