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:
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.
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:
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:
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:
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!




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
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
@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
Obrigado por prestigiar o blog
@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.
E isso ae Stefan muito bom o artigo. Parabéns!
@Carlos Lima
Obrigado por visitar o blog
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
Valeu Janderson, e obrigado pela visita!
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??
Bah tche…
Parabéns pelo post.
Simples e direto… não conhecia o FlexORM, gostei pela praticidade =)
Abraços e até mais
GuiSjlender
@Guilherme, Valeu! Obrigado por visitar o blog e comentá-lo!
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