terça-feira, 30 de janeiro de 2018

DROP Wiki (English) #1 - Introduction

Você pode ler este post em português clicando aqui.

With the main goal of providing large documentation about the DROP, I'll start the series DROP Wiki, and as lots of conversations about the framework start with the question "What is the DROP?", nothing better than to start the series by trying to answer this question.

Using the shortest possible answer, the DROP is a set of classes built in Delphi, to make the daily tasks of the developer easier. A bunch of these classes have been developed to support their own ORM framework (object relational mapping), and it is mainly for fulfilling this goal that the DROP is best known.

Another great thing about the DROP is that it is a totally free and open source (MIT license), and if you are already interested in downloading or using it, you can do it through GitHub, or by downloading the source in a compacted file using this link. Now, lets break the DROP down a little further.

I remember that, while developing/rewriting the DROP, for many times I have talked with my teammates at Aquasoft, or among other developers (as my friend Muka), and the subject of these conversations was the reason of the DROP having been divided into some layers, each of them with one responsibility. Understanding these layers can make the understanding of the whole DROP easier:
  • Core: contains useful classes for several tasks, with generic development purposes. On this layer there's nothing implemented to access DBMSs. To tell you the truth, some classes are not even used directly or indirectly in ORM tasks;
  • DB: the classes contained here abstract the communication with DBMSs, and therefore, many of these classes are abstract as well, providing uniform structures, that further allows to DROP write code once, however compatible with the supported DBMSs. Even though on this level there aren't concrete classes to access data, there are lots of specific classes to some DBMSs, like the classes that solve the SQL objects, translating them into the specific language of each of the supported DBMSs;
  • ORM: contains the ORM classes, proper. They transform classes structures and their attributes to SQL objects, as enable those entities objects to be persisted and retrieved from the DBMSs;
  • ORM Base (I still think that this name needs a facelift from a marketing department ;-): the ORM layer doesn't requier that the classes to be mapped inherit from the DROP classes, however, the DROP provides, by this layer, some classes that can be extended, reducing the developer work while doing the ORM.
The Core layer presents all its units in a namesake package, being that all other layers are implemented in a package called DB. It is important to emphasize that all classes contained in these packages are free from specific any data access engines.

To perform the physical data access, the DROP can work with both DBX Framework or FireDAC. It is up to the developer to use one technology or the other. Therefore, each of the implementation of the DROP to the above technologies has received its own package.

Talking about physical data access, the DROP currently supports seven relational DBMSs:
  • Interbase;
  • Oracle;
  • Microsoft SQL Server;
  • PostgreSQL (only by FireDAC);
  • MySQL;
  • Firebird;
  • SQLite (ok, not really a DBMS, but...).
Concluding, if it were possible to summarize the above content in an image, it would be something like this:



Finishing this post, the sequence of these serie are still being written (some of the Portuguese posts are already published, and I'll work in the translation ASAP). The next posts will cover the above topics alternating topics between all the DROP layers.

Thank you for reading! See ya!

terça-feira, 7 de novembro de 2017

DROP Wiki #4 - Transações

O post de hoje é extremamente simples, mas sobre algo muito importante: Transações!




O sistema de transações do DROP trabalha com o conceito de chamadas cumulativas. E o que isto quer dizer?

Nota: O exemplo a seguir é uma versão resumida do que podemos encontrar em produção, mas demonstra bem o conceito do sistema de transações do DROP (não queime neurônios discutindo se você resolveria com uma estrutura de classes diferentes ou não, se concentre no recurso apresentado).


Começaremos com uma classe de nome TProduto. Esta possui um método que, entre outros, trata a movimentação do estoque deste produto. Toda movimentação deve atualizar o campo de saldo de estoque do produto, e também incluir um registro de detalhamento da movimentação. Este método deve ser auto-suficiente, e consequentemente, se responsabilizar pela garantia de que os dados armazenados são consistentes, o que com certeza demandará o uso de transação com o banco, concorda? Se você concorda, este método seria escrito mais ou menos assim:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
procedure TProduto.Movimentar(const pIDDocumento: UInt32; 
  const pMovimentacao: Currency);
begin
  ConexaoDoDROP.StartTransaction;

  try
    ConexaoDoDROP.ExecuteCommand('update estoque_produto ...');
    ConexaoDoDROP.ExecuteCommand('insert into movimento_estoque ...');

    ConexaoDoDROP.CommitTransaction;
  except
    ConexaoDoDROP.RollbackTransaction;
    raise;
  end;
end;

Pois bem, imagine que outra classe, de nome TVenda, possui um método responsável por consolidar uma venda de produtos no banco de dados. Este método registra os dados da venda em diversas tabelas, e como neste momento a venda está sendo consolidada, o estoque dos produtos também deve ser movimentado. Como bom programador, você deve estar pensando em reutilizar o método anterior para persistir a nova posição do estoque, certo? Vamos ao código de TVenda.Consolidar:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
procedure TVenda.Consolidar;
var
  lItem: TVendaItem;
begin
  ConexaoDoDROP.StartTransaction;

  try
    ConexaoDoDROP.ExecuteCommand('insert into venda ...');

    for lItem in Itens do
    begin
      ConexaoDoDROP.ExecuteCommand('insert into venda_item ...');
      lItem.Produto.Movimentar(Self.ID, lItem.Quantidade);
    end;

    ConexaoDoDROP.CommitTransaction;
  except
    ConexaoDoDROP.RollbackTransaction;
    raise;
  end;
end;

Muitos desenvolvedores optam por esta solução. No entanto, o que acontece com a sua engine de acesso a dados se você chamar uma segunda vez o comando de início de transação, sem ter terminado a transação anterior? Algumas engines não suportam esta técnica, e portanto, várias alternativas de workaround normalmente são implementadas, como testar se a conexão já possui uma transação aberta, ou delegar a abertura da transação para outro método, entre outras.

O sistema de chamadas cumulativas de transações do DROP permite que o comando de início da transação possa ser chamado mais de uma vez, sem que tenha que existir o desfecho da transação entre estas chamadas. Claro que, para que este sistema faça sentido, todas as chamadas de início de transação devem ser finalizadas também cumulativamente.

Concluindo, o DROP permite que, tanto o código de TProduto.Movimentar possa ser chamado individualmente, quanto possa ser reutilizado em outras rotinas já com transação aberta, sem que você precise escrever qualquer desvio para que isto tudo aconteça.

Era isto, até o próximo post!

Episódio Anterior Próximo Episódio

sexta-feira, 3 de novembro de 2017

DROP 1.3.1 - Edição Especial Embarcadero Conference 2017


Conforme anunciado antes mesmo do evento, saiu a nova versão do DROP, em edição especial para a Embarcadero Conference 2017. A nova versão está liberada nos tradicionais canais de distribuição:


Os esforços para esta versão se concentraram no suporte ao Interbase (nova feature), total tradução dos testes automatizados para a nova plataforma de testes, e claro, diversas pequenas melhorias foram realizadas.

Quer ajudar a desenvolver o DROP? Fique à vontade para enviar Pull Requests pelo GitHub.

Tem dúvidas de como usar o DROP ou quer entrar em contato para trocar ideias? Por favor, envie seu e-mail para drop@aquasoft.com.br.

E para fechar, novos posts sobre o DROP já estão em produção. Aguarde, pois muitas novidades estão por vir!!!

quinta-feira, 26 de outubro de 2017

Embarcadero Conference 2017

Hoje estou dando uma passada rápida aqui só para registrar que a Embarcadero Conference deste ano foi demais!!!

Obrigado a todos os participantes, especialmente aos que prestigiaram minhas apresentações! Me sinto honrado em merecer a atenção de vocês!


Nota importante: A versão especial do DROP para a Embarcadero Conference (1.3.1 - conforme prometido) já foi publicada. Os participantes do evento receberão via e-mail as instruções de como obtê-la.

Auditório principal durante a abertura do evento.

Momento de break, e muito networking.

Durante a minha primeira apresentação.

Meu muito obrigado aos expectadores!

Tradicional foto com os palestrantes e MVPs.


Embarcadero Conference 2018, nos aguarde!

sexta-feira, 6 de outubro de 2017

DROP Wiki #3 - Instruções SQL via texto

Por mais que um ORM tenha o objetivo de não escrever explicitamente instruções SQL, usuários novos de ORMs tendem a não aceitar uma ferramenta que não permita usar uma instrução SQL escrita manualmente. Em outras palavras, a aceitação de um framework com suporte a ORM passa por também suportar SQLs via texto, é quase que uma válvula de escape para desenvolvedores que não dominam ou até mesmo não confiam 100% na técnica.

No post anterior, foi apresentada a lista de classes nativas do DROP para estabelecimento de conexões com os SGBDs suportados. Como estratégia de evolução na apresentação e uso dos recursos do DROP, este post demonstrará como conversar com o SGBD, via instruções SQL escritas manualmente.

Os exemplos a seguir serão implementados sobre o Interbase, mas como já mencionado no post anterior, os recursos apresentados aqui estão disponíveis para todos os SGBDs suportados pelo DROP. Para os exemplos abaixo, assuma que já existe um objeto de conexão instanciado, e apontando para a tradicional base de exemplos Employee.

Inicialmente, o DROP não possui componentes ou objetos a parte para executar os comandos, como os tradicionais TSQLQuery, TFDQuery, entre outros. Todos os acessos e manipulações de dados são executados diretamente a partir do objeto de conexão com o SGBD.

Para começar, vamos buscar dados através de um select simples. As instruções SQL que retornam cursores são executadas através do método OpenQuery. Uma das sobrecargas do OpenQuery permite passar diretamente o texto de um select (demais sobrecargas serão demonstradas em outro post). Todas as sobrecargas do método OpenQuery retornam uma implementação da interface IAqDBReader.

A interface IAqDBReader foi especificada visando ser uma camada de acesso muito fina entre o seu código e os dados do cursor aberto pela instrução SQL. Portanto, o retorno não faz cache, e é unidirecional. Também é muito importante dizer que a leitura do primeiro registro passa obrigatoriamente pela primeira chamada do método Next no reader (ao estilo DBX Framework e readers de outras linguagens). E por fim, existem duas maneiras de ler colunas do cursor, as tradicionais referências por índice ou nome das mesmas.

O exemplo abaixo demonstra a leitura de todos os países da base, e então a alimentação de um componente memo com cada um dos nomes retornados.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
procedure TfrmExemplos.btnSelectClick(Sender: TObject);
var
  lReader: IAqDBReader;
begin
  mmoResultados.Lines.Clear;

  lReader := FConexao.OpenQuery('select country from country');

  while lReader.Next do
  begin
//    mmoResultados.Lines.Add(lReader.Values[0].AsString);
    mmoResultados.Lines.Add(lReader.Values['country'].AsString);
  end;
end;

Note que no laço de alimentação do memo constam duas linhas. A primeira linha, que está comentada e, portanto, sem efeito, o índice da coluna seria usado para referenciá-la, e na segunda linha, acessamos o valor da coluna através do seu nome.

Aos que não estão habituados com este conceito de reader, é necessário salientar que o método Next já é responsável por informar se o cursor chegou ao seu fim ou não, fazendo com que o teste de quebra do laço realize a troca do registro apontado pelo cursor.

O próximo exemplo visa demonstrar uma variação do exemplo acima, desta vez criando um parâmetro para execução da consulta.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
procedure TfrmExemplos.btnSelectComParametrosClick(Sender: TObject);
var
  lReader: IAqDBReader;
begin
  mmoResultados.Lines.Clear;

  lReader := FConexao.OpenQuery(
    'select country from country where currency = :currency',
    procedure(pParametros: IAqDBParameters)
    begin
      pParametros['currency'].AsString := 'Euro';
    end);

  while lReader.Next do
  begin
    mmoResultados.Lines.Add(lReader.Values['country'].AsString);
  end;
end;

É possível observar que a criação de parâmetros segue o tradicional padrão de quase todas as engines de acesso a dados do Delphi, com a prefixação do parâmetro com o caractere ':'. A principal diferença do DROP às demais metodologias está na passagem dos valores dos parâmetros, que acontece com um método anônimo (callback) que dá acesso aos parâmetros antes da execução da instrução contra o SGBD.

Como nota importante do exemplo acima, é importante dizer que, mesmo quando usando o DBX Framework como engine da conexão do DROP, o método de parâmetros nomeados também está disponível. Para quem não lembra, o DBX Framework não suporta parâmetros nomeados, mas o DROP realiza um parse sobre a instrução SQL, mapeia os parâmetros, e então faz o meio de campo entre os parâmetros do DBX e os parâmetros disponibilizados ao usuário, podendo estes serem acessados também via nome.

Por fim, vamos a um exemplo de instrução de DML. Estes comandos são executados a partir do método ExecuteCommand, que entre outras sobrecargas, também possui a capacidade de receber uma instrução de DML via texto, e passagens dos parâmetros via callback. Observe o exemplo abaixo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
procedure TfrmExemplos.btnUpdateClick(Sender: TObject);
var
  lRegistrosAfetados: Int64;
begin
  lRegistrosAfetados := FConexao.ExecuteCommand(
    'update country set currency = :currency where country = :country',
    procedure(pParametros: IAqDBParameters)
    begin
      pParametros['currency'].AsString := 'US Dollar';
      pParametros['country'].AsString := 'USA';
    end);

  ShowMessage(lRegistrosAfetados.ToString);
end;

Dúvidas? Por favor, não hesite em me contatar através do mail tatu@taturs.com, ou ainda por drop@aquasoft.com.br.

Abraço e até o próximo post!

Episódio Anterior Próximo Episódio

sexta-feira, 8 de setembro de 2017

DROP Wiki #2 - Conexões com SGBDs

You can read this post in english here.

Dando continuidade à série DROP Wiki, o assunto da vez é o estabelecimento da conexão com uma fonte de dados (normalmente um SGBD) e a escolha da melhor classe para realizar esta tarefa.

Mais adiante veremos que para o ORM do DROP funcionar, poucos pré-requisitos são necessários. Destes pré-requisitos, o mais importante com certeza é criar um objeto do tipo TAqDBConnection, e através deste objeto, estabelecer uma conexão com a fonte de dados.

A classe TAqDBConnection (unit AqDrop.DB.Connection) é quase totalmente abstrata (existem planos, ainda que remotos, para transformá-la em interface, o que pode facilitar a implementação de testes). A responsabilidade da classe é abstrair o mínimo necessário para execução de comandos pelos SGDBs suportados. Obviamente, esta abstração visa possibilitar a extensão do framework para diferentes engines de acesso, sendo que, não custa relembrar, já temos extensões implementadas para DBX e FireDAC.

Basicamente as interfaces fornecidas por TAqDBConnection são:
  - Rotinas para manipulação de Transações;
  - Preparação de comandos (ao estilo Prepare e Unprepare);
  - Rotinas para abertura de cursores;
  - Rotinas para execução de comandos (normalmente DMLs);

As rotinas de manipulação de transações, preparação e execução de comandos não diferem muito de qualquer engine de acesso a dados do Delphi (inclusive de terceiros). A diferença mais significativa está nas rotinas de abertura de cursores, que foram construídas de forma a fornecer interfaces semelhantes às fornecidas pelos readers do DBX Framework, conferindo ao código de leitura dos cursores um aproach mais voltado à orientação a objetos (em resumo, no DataSets ;-).

Visando dividir os trabalhos do suporte ao DBX e FireDAC, duas classes foram implementadas e, ao estilo VCL, ambas tem o termo 'Custom' em seus nomes (TAqDBXCustomConnection e TAqFDCustomConnection), realizando o trabalho pesado no que diz respeito a alcançar seus respectivos objetivos. Duas heranças diretas, omitindo o termo 'Custom' de seus nomes (TAqDBXConnection e TAqFDConnection) tem somente o trabalho de disponibilizar ao usuário da classe todos os parâmetros fornecidos pelo DROP e as engines mapeadas, de forma a permitir a configuração completa para acesso ao SGBD desejado.

Conforme prometido em outras oportunidades, uma feature que estava no forno e agora está pronta (faltando somente terminar a escrita dos novos testes para liberar a publicação), é o suporte ao Interbase. Já que esta é uma novidade, aproveito a oportunidade para usar o SGDB da Embarcadero para demonstrar, via DBX, a configuração de uma conexão. Segue exemplo de uso da classe TAqDBXConnection:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function TTesteConexaoDBXConnection.GetConexao: TAqDBConnection;
var
  lConexao: TAqDBXConnection;
begin
  lConexao := TAqDBXConnection.Create;

  try
    lConexao.DriverName := 'InterBase';
    lConexao.VendorLib := 'GDS32.DLL';
    lConexao.LibraryName := 'dbxint.dll';
    lConexao.GetDriverFunc := 'getSQLDriverINTERBASE';
    lConexao.Properties[TDBXPropertyNames.Database] := 'C:\ALGUMCAMINHO\ALGUM.GDB';
    lConexao.Properties[TDBXPropertyNames.Username] := 'SYSDBA';
    lConexao.Properties[TDBXPropertyNames.Password] := 'masterkey';
    lConexao.DBXAdapter := TAqDBXIBAdapter.Create;
  except
    lConexao.Free;
    raise;
  end;

  Result := lConexao;
end;

O exemplo acima mostra que configurar uma conexão do DROP ou um TSQLConnection, por exemplo, são tarefas muito parecidas. No entanto, uma diferença clara da configuração do DROP para outras conexões do Delphi, está na construção de um adapter, necessário para um completo funcionamento dos recursos do DROP. Os adapters informam ao DROP como resolver algumas tarefas, ou então, como ler alguns tipos de dados do SGDB.

Como o DROP visa funcionar mais como biblioteca, e menos como componente, a tarefa acima pode ser simplificada através do uso de um outro conjunto de classes, que mapeiam mais facilmente algumas distinções entre os SGBDs suportados. Abaixo vemos a criação de uma conexão com a mesma base de dados utilizada acima, no entanto, usando diretamente uma classe que mapeia DBX e as particularidades do Interbase.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
function TTesteConexaoDBXIB.GetConexao: TAqDBConnection;
var
  lConexao: TAqDBXIBConnection;
begin
  lConexao := TAqDBXIBConnection.Create;

  try
    lConexao.DataBase := 'C:\ALGUMCAMINHO\ALGUM.GDB';
    lConexao.UserName := 'SYSDBA';
    lConexao.Password := 'masterkey';
  except
    lConexao.Free;
    raise;
  end;

  Result := lConexao;
end;

No exemplo acima percebemos que a classe TAqDBXIBConnection se responsabiliza por configurar as propriedades conforme padrão para conectar com o Interbase, e expõe propriedades que são específicas do IB. Estas propriedades permitem configurar estaticamente alguns dados como o percurso do GDB, usuário e senha, ao contrário do primeiro exemplo, onde estas informações são dadas dinamicamente.

Bom, este foi o exemplo com o SGDB Interbase, e exemplos com outros SGDBs simplesmente significariam um pouco "mais do mesmo" em se tratando de código. No entanto, é válido colocar no mínimo a lista de classes especializadas já disponíveis no DROP, cada uma configurando a conexão para o comportamento padrão do SGDB, e disponibilizando propriedades particulares ao mesmo. Segue lista completa de classes, separadas por engine:

DBX:
 - TAqDBXIBConnection;
 - TAqDBXMSSQLConnection;
 - TAqDBXMySQLConnection;
 - TAqDBXFBConnection;
 - TAqDBXOraConnection;
 - TAqDBXSQLiteConnection;

FD:
 - TAqFDIBConnection;
 - TAqFDMSSQLConnection;
 - TAqFDMySQLConnection;
 - TAqFDFBConnection;
 - TAqFDOraConnection;
 - TAqFDSQLiteConnection;
 - TAqFDPGConnection;

Notem que no FireDAC, temos um SGDB a mais, que é o PostgreSQL.

E, para o momento, vamos ficando por aqui. Na sequência teremos o episódio #3 da série, que vai mostrar como usar estes objetos de forma independente, e em episódios futuros, como usar dentro do aspecto do mapeamento objeto-relacional.

Até o próximo post!




terça-feira, 6 de junho de 2017

DROP Wiki #1 - Introdução

You can read this post in english here.

Com o objetivo de fornecer documentação extensa sobre o DROP, vou começar a série DROP Wiki, e como muitas conversas sobre o framework começam pela pergunta "O que é o DROP?", nada melhor do que começar a série tentando responder esta pergunta.

De forma mais resumida possível, O DROP é um conjunto de classes feitas em Delphi, para facilitar tarefas do cotidiano do desenvolvedor. Muitas destas classes foram desenvolvidas para suportar um framework próprio de ORM (mapeamento objeto-relacional), e é principalmente por cumprir este objetivo que o DROP é mais conhecido.

Outra coisa importante sobre o DROP é que ele é totalmente grátis e open source (licença MIT), e se você já está interessado em baixá-lo ou usá-lo, você pode fazer através do GitHub, ou fazendo o download dos fontes através de um arquivo compactado neste link. Agora, vamos esmiuçar mais um pouco o DROP.

Lembro que, enquanto o DROP estava sendo desenvolvido/remodelado, muitas vezes conversei com a equipe da Aquasoft e outros desenvolvedores (como meu amigo Muka), e o assunto de várias destas conversas era o porquê do DROP ser dividido em algumas camadas, cada camada com uma responsabilidade. Entender melhor estas camadas, faz com que o entendimento sobre o DROP seja facilitado:

  • Core: contém classes úteis para diversas coisas, com fins genéricos no desenvolvimento em geral. Nesta camada ainda não há nada implementado para acessar ou conversar com SGBDs. Para falar a verdade, algumas classes nem chegam a ser consumidas direta ou indiretamente nas tarefas de ORM;
  • BD: as classes contidas aqui abstraem a comunicação com SGBDs, e consequentemente, muitas destas classes são abstratas, fornecendo estruturas uniformes, que mais adiante permitem ao DROP escrever o código uma única vez, porém compatível com todos os bancos de dados suportados até então. Por mais que neste nível não existam classes concretas de acesso a dados, já existem muitas classes específicas para alguns SGBDs, como as classes que resolvem os objetos de SQL, traduzindo-os para a linguagem específica de cada um dos SGBDs suportados;
  • ORM: contém as classes de ORM, propriamente ditas. Transformam estruturas de classes e seus atributos em objetos SQL, bem como possibilitam com que objetos que representam entidades sejam persistidas e recuperadas dos SGBDs;
  • Base para ORM (este nome ainda precisa de um facelift do setor de marketing ;-): a camada de ORM não exige que as classes a serem mapeadas herdem de classes do DROP, no entanto, o DROP fornece, nesta camada, algumas classes que podem ser estendidas, reduzindo o trabalho do desenvolvedor ao realizar o mapeamento objeto-relacional.

A camada Core apresenta todas as suas units em um pacote homônimo, sendo que as demais camadas estão implementadas no pacote DB. É importante salientar que todas as units das camadas acima estão livres de código específico para acesso a dados via alguma das tecnologias para tal tarefa.

Para realizar o acesso físico aos dados, o DROP pode trabalhar tanto com o DBX framework, quanto FireDAC, fica a critério do desenvolvedor usar uma tecnologia ou outra. Sendo assim, cada uma das implementações do DROP para as tecnologias acima recebeu seu próprio pacote.

Falando em acesso físico a dados, o DROP atualmente suporta seis SGBDs relacionais:
  • Interbase;
  • Oracle;
  • Microsoft SQL Server;
  • PostgreSQL (somente via FireDAC);
  • MySQL;
  • Firebird;
  • SQLite.
Concluindo, se fosse possível resumir o conteúdo acima com uma imagem, seria mais ou menos assim:




Para encerrar, os próximos posts da série alternarão assuntos de como usar ORM, bem como as classes que circundam todo o eco-sistema. Até lá!!!

Próximo Episódio

Você está fazendo isso errado! Tópico #2

 Fala galera! Como estão todos? Sejam bem-vindos ao primeiro post de 2021. Continuando o tema "Você está fazendo isso errado", va...