Blog – FAQ 4

Blog - FAQ 4Olá, pessoal. Hoje é dia de publicar mais um FAQ dos leitores do blog. Agradeço novamente a todos os leitores pelas visitas, comentários, sugestões e divulgação do conteúdo nas redes sociais. Aproveito para fazer um grande agradecimento ao Jackson Caset, mantenedor do portal Profissionais TI, por replicar alguns artigos do blog no site.

 

Existe muita diferença entre MVC, MVP, MVVM e MGM?
Sim, há algumas diferenças entre esses padrões de arquitetura, principalmente relacionadas às responsabilidades de cada camada, comportamentos dos objetos e a forma como as interações são implementadas. Embora tenham objetivos em comum, os padrões se diferem na forma como são manipulados na arquitetura do projeto. Vale lembrar que estes padrões são flexíveis, logo, nada impede que um desenvolvedor estenda as camadas com novas responsabilidades ou modifique regras de interação, desde que não fuja das diretrizes que o padrão propõe.
Explicar cada um dos padrões resultaria em uma resposta muito extensa, portanto, sugiro acessar este link para compreender melhor as diferenças entre eles. O artigo apresenta características bem detalhadas de cada padrão.
Além dos quatro padrões mencionados nessa questão, há também o MOVE, no qual já publiquei um artigo a respeito. O MOVE sugere uma estrutura um pouco diferente quando comparada aos outros padrões, mas traz uma boa proposta de arquitetura.

 

Gostaria de utilizar um arquivo INI para armazenar o caminho do banco de dados. Qual o procedimento para ler a chave do arquivo INI e realizar a conexão?
Para ler o caminho do banco de dados do arquivo INI e atribui-lo à aplicação, você pode escrever o código abaixo no evento que é disparado antes da conexão. Se você estiver utilizando dbExpress ou IBX, utilize o código no evento BeforeConnect do SQLConnection / IBDatabase.

var
  CaminhoArquivoINI: string;
  CaminhoBancoDeDados: string;
  ArquivoINI: TIniFile;
begin
  CaminhoArquivoINI := ExtractFilePath(Application.ExeName) + 'ArquivoINI.ini';
  ArquivoINI := TIniFile.Create(CaminhoArquivoINI);
 
  CaminhoBancoDeDados := ArquivoINI.ReadString('Configuracao', 'CaminhoBancoDeDados', ''); 
  SQLConnection1.Params.Values['Database'] := CaminhoBancoDeDados;
 
  ArquivoINI.Free;
end;

A primeira linha carrega o arquivo INI na mesma pasta onde está o executável.
Em seguida, a segunda linha lê o caminho do banco de dados e atribui ao componente de conexão.
Por fim, a terceira linha libera o arquivo da memória.

 

O ideal para conexão com o banco de dados de forma dinâmica é somente por arquivo INI ou possui algum gerenciador que efetue melhor esse controle?
Na empresa em que eu trabalhava, uma vez houve uma discussão sobre qual recurso utilizar para armazenar os parâmetros de conexão com o banco de dados, entre eles, o caminho. Até o momento, a empresa ainda utiliza arquivos INI principalmente pela simplicidade de manipulação e por ser um arquivo com tamanho pequeno. Mesmo assim, além do arquivo INI, pode-se utilizar também arquivos XML.
Outra alternativa é utilizar o registro do Windows para armazenar estes valores. Neste caso, não haverá um arquivo físico exclusivo, já que o registro do Windows é gravado de uma forma “abstrata”.
Alguns desenvolvedores criam gerenciadores para administrar os parâmetros de conexão. Você pode, por exemplo, criar um gerenciador gráfico com caixas de texto e um navegador de pastas para manipular automaticamente o arquivo INI. Isso evita a necessidade de editar manualmente o arquivo INI, o que exige um conhecimento prévio de sua estrutura.

 

No meu projeto, estou implementando a funcionalidade de exclusão de uma venda. Essa funcionalidade deve deletar também todos os itens da venda selecionada. Como devo implementá-la?
Há muitas maneiras de remover os detalhes antes de excluir o registro mestre. Aqui vou apontar algumas delas.
Considere que o nome da tabela mestre seja VENDAS e a tabela de detalhes se chame ITENSVENDA.
Uma das maneiras é fazer um loop no DataSet da tabela ITENSVENDA e excluir todos os itens da venda selecionada. Você pode usar o evento BeforeDelete do DataSet da tabela VENDAS para disparar essa operação. O evento BeforeDelete é disparado ANTES do registro ser excluído, portanto, podemos pensar da seguinte forma: ANTES da venda ser excluída, exclua os itens primeiro:

begin
  cdsItensVendas.First;
  while not cdsItensVendas.Eof do
    cdsItensVendas.Delete;
 
  cdsItensVendas.ApplyUpdates(0);
end;

Obs: no código acima não é preciso utilizar o Next, já que, ao deletar um registro, o DataSet automaticamente já move para o registro seguinte.

Outra maneira de implementar essa funcionalidade é via SQL. Neste caso, você pode optar por fazer ANTES ou DEPOIS da venda ser excluída. Basta utilizar uma Query para remover os itens:

Query1.SQL.Clear;
Query1.SQL.Add('Delete from ITENSVENDA');
Query1.SQL.Add('where Codigo = :Codigo');
Query1.ParamByName('Codigo').AsInteger := {aqui você atribui o número da venda};
Query1.ExecSQL;

Uma maneira mais confiável (porém, mais avançada) é utilizar Triggers para remover os itens.
Se você tem um bom conhecimento em SQL, considere criar uma Trigger no banco de dados para remover os itens quando a venda for excluída.
Eu desenvolvi um sistema de gestão de pedidos e utilizo essa opção para realizar essa operação. Quando o usuário exclui um pedido, uma Trigger é disparada no banco de dados para que os itens também sejam automaticamente excluídos. Uma das vantagens de criar Triggers é a economia de código do lado da aplicação, já que elas são criadas no banco de dados.

 

Em POO, utilizar tabelas temporárias para tratar um relacionamento mestre/detalhe quebra o paradigma MVC? Para manter o MVC, a composição deveria ser feita de outra forma? Se sim, como?
Na abordagem do MVC, geralmente o registro mestre e os detalhes são tratados como objetos em um relacionamento master/detail. Por exemplo, o desenvolvedor pode criar uma classe chamada “Venda” e, dentro dessa classe, criar uma lista de objetos da classe “ItensVenda”. Isso dá sentido à composição, ou seja, ao instanciar um objeto da classe “Venda”, a aplicação automaticamente cria uma lista de itens (details). Na prática, durante o cadastro de uma venda, basta preencher um objeto dessa classe (adicionando cada item na lista de objetos) e enviá-lo para a camada de persistência. Essa camada irá gravar o registro mestre e percorrer os detalhes (lista de objetos), gravando-os no banco de dados.
Por outro lado, nada impede que você utilize tabelas temporárias. Ao invés de alimentar um objeto, você pode popular uma tabela temporária criada em tempo de execução. No método de gravação, percorra os registros da tabela temporária e, para cada registro, preencha um objeto que será enviado para a camada de persistência.
O conceito pode parecer um pouco complexo, mas é bastante funcional dentro do contexto da Orientação a Objetos.

 

Até a próxima semana, leitores!


Confira também os outros FAQs:

FAQ 01 | FAQ 02 | FAQ 03 | FAQ 04 | FAQ 05 | FAQ 06 | FAQ 07 | FAQ 08 | FAQ 09


 

Compartilhe!
Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+Pin on PinterestEmail this to someone

2 comentários

  1. Ola, André.

    No caso de exclusão/cancelamento de venda uso o triggers, um no pedido exclui os lançamentos e parcelas em contas a receber e aciona outro na exclusão dos itens que atualiza o estoque.
    Programar usando os recursos do BD é ótimo, pra mim a melhor solução, quanto mais eu aprender e conseguir passar tarefas para o BD será melhor.
    O que acha?

    1. Sim, Gerson, tratar regras de negócio no Banco de dados (através de Stored Procedures e Triggers) é uma ótima opção, principalmente por dispensar codificação no lado do cliente. No entanto, é preciso ter bom senso. Devemos nos atentar que a execução desses recursos exige processamento da engine do banco de dados, logo, se houver 1000 usuários compartilhando o mesmo banco, o desempenho pode ser prejudicado.
      Essa análise de impacto deve ser discutida nas etapas iniciais do projeto, baseada no ambiente de produção que o software irá operar.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Preencha o campo abaixo * Time limit is exhausted. Please reload CAPTCHA.