Blog – FAQ 3

Blog - FAQ 3Saudações, pessoal. Uma das grandes vantagens da internet é a possibilidade de encontrar respostas para as nossas dúvidas e expandir o nosso conhecimento. Fico motivado em contribuir com esse base de informações, já que  eu também pesquiso várias coisas na internet. Por este motivo, volto com o terceiro FAQ abordando mais algumas dúvidas dos caros leitores. A intenção é compartilhar o conhecimento e colaborar com profissionais que tenham as mesmas dúvidas.

 

Qual o procedimento para implementar permissões de acesso no Delphi?
Há basicamente 2 formas de implementar o esquema de permissões de acesso.
A primeira delas, mais fácil, consiste em classificar cada usuário pelo seu nível de permissão.
Por exemplo, suponha que tenhamos 3 níveis: Administrador, Gerente e Operador:

  • O Administrador tem acesso à todos os formulários;
  • O Gerente tem acesso à todos os formulários, exceto os de configuração do sistema;
  • O Operador tem acesso somente aos formulários operacionais, como cadastros básicos e emissão de vendas.

Dessa forma, no formulário de login, você pode implementar uma rotina que faz a leitura o nível do usuário e habilite/desabilite os menus conforme necessário, como no exemplo abaixo:

var
  UsuarioAdministrador: boolean;
  UsuarioGerente: boolean;
begin
  UsuarioAdministrador :=
    TabelaUsuarios.FieldByName('Permissao').AsString = 'Administrador';
  UsuarioGerente :=
    TabelaUsuarios.FieldByName('Gerente').AsString = 'Administrador';
 
  // menus do nível "Administrador"
  MenuConfiguracoes.Visible := UsuarioAdministrador;
  MenuAdministracao.Visible := UsuarioAdministrador;
  MenuCadastroUsuarios.Visible := UsuarioAdministrador; 
 
  // menus do nível "Gerente"
  MenuRelatorioGerencial.Visible := UsuarioAdministrador or UsuarioGerente;
  MenuFaturamento.Visible := UsuarioAdministrador or UsuarioGerente;
  MenuHistoricoVendas.Visible := UsuarioAdministrador or UsuarioGerente;
end;

A segunda forma, mais difícil, baseia-se em configurar os níveis de acesso por menu.
Por exemplo, durante o cadastro do usuário, a aplicação disponibiliza uma tela para selecionar quais os menus que ele pode acessar, mais ou menos nesse padrão:

Exemplo de tela para configuração de permissão de acesso

Porém, neste caso, você terá que criar mais uma tabela (“Permissões”, por exemplo) para armazenar os menus que o usuário pode acessar.
De um modo mais prático, a segunda forma não deixa de ser um relacionamento Master/Detail.

 

Notei que há muito código duplicado no meu projeto. É possível melhorar o meu código nesse aspecto?
É possível sim! Existe uma técnica na área de programação conhecida como Clean Code. Um dos conceitos dessa técnica consiste na prática de Refatoração, ou seja, extrair uma porção do código-fonte que é utilizada em mais de um local no projeto.
No seu código, você pode praticar a Refatoração e mover as linhas duplicadas para um método. Em seguida, nos locais onde as linhas estavam duplicadas, basta chamar este método. Isso inclusive contribui para facilitar a manutenção.
Para contribuir com a minha resposta, sugiro que você leia o artigo sobre Sub-Rotinas aqui mesmo no blog.
Além disso, muita coisa pode ser melhorada com a utilização de Design Patterns, apesar de exigir um pouco mais de domínio em orientação a objetos.

 

Como funciona a parametrização em uma Query no Delphi?
Os parâmetros se originam da SQL que é atribuída à Query.
Observe bem essas linhas:

Query1.SQL.Add('Select * from CLIENTES');
Query1.SQL.Add('where Nome like :Nome');

Neste momento, estou criando um parâmetro chamado “Nome” que será preenchido por algum valor em tempo de execução. Agora, suponha que o usuário digitou “JOAO” na Edit1. Nas linha abaixo, eu informo que o parâmetro devem receber esse valor:

Query1.ParamByName('nome').AsString := QuotedStr(Edit1.Text + '%');
Query1.Open;

Portanto, mesmo que não seja visível ao usuário (e nem ao desenvolvedor), a consulta que será enviada para o banco de dados será essa:

SELECT * FROM CLIENTES
WHERE Nome LIKE 'JOAO%'

O ParamByName simplesmente substitui o parâmetro por um valor em tempo de execução.
Observe também que para criar um parâmetro na Query é necessário colocar os dois pontos ( : ) antes do nome do parâmetro na SQL.

 

(a questão seguinte é um complemento da dúvida anterior)
Gostaria de montar um Select (SQL) que retorne os itens de uma determinada venda.
A situação que você mencionou é bastante comum no desenvolvimento de software e normalmente utilizamos parâmetros na Query para implementá-la. Uma das formas para realizar essa consulta é:

Query1.Close; // fecha a Query
Query1.SQL.Clear; // limpa a propriedade SQL
Query1.SQL.Add('Select CodProduto, Qtde, ValorUnitario, ValorTotal'); // campos
Query1.SQL.Add('from ItensVenda'); // tabela
Query1.SQL.Add('where Venda = :Venda'); // condição e criação do parâmetro
Query1.ParamByName('Venda').AsInteger := 10; // preenchimento do parâmetro
Query1.Open; // traz somente os itens da venda 10

No exemplo acima, basta atribuir o valor desejado ao parâmetro “Venda” na linha do ParamByName.
Você também pode incluir cláusulas Join nesse Select, caso a tabela ItensVenda faça referência a outras tabelas (como Produto, para buscar a descrição do item).

 

No artigo sobre MVC, observei que voce faz a validação dos dados (regra de negócio) no próprio controlador. Não seria uma boa prática criar uma camada de negócio pra realizar as validações dentro do controlador e usá-lo apenas para direcionar as requisições?
Boa observação! Essa questão gera muita controvérsia. No exemplo que desenvolvi no artigo, decidi colocar as regras de negócio no Controller, manter o Model exclusivamente para as classes de modelagem e a camada DAO para persistência de dados com o objetivo de demonstrar a separação de responsabilidades. Porém, muitos desenvolvedores empregam uma estrutura mais gerenciada: o Model agrega tanto as classes de modelagem quanto as regras de negócio, enquanto o Controller somente assume a fronteira entre a View e o Model.
Na empresa em que trabalho, optamos por utilizar o MVP (Model-View-Presenter) nessa estrutura que você mencionou, e é bastante funcional. Toda a regra de negócio é concentrada na camada Model, dispensando o Presenter dessa responsabilidade. Os resultados até o momento foram positivos.

 

Quais as principais vantagens e desvantagens entre programar com DAO (Data Access Object) e ORM (Object Relational Mapping)?
Ótima pergunta.
Tanto DAO quanto ORM são camadas de persistência, mas o ORM tira mais proveito da Programação Orientada a Objetos. O objetivo do ORM é evitar que haja um retrabalho ao criar a modelagem das tabelas no banco de dados e a modelagem das classes que representam essas tabelas. Em outras palavras, o ORM permite que, por exemplo, uma ferramenta leia a estrutura de uma tabela e gere uma classe que a represente (em que os campos da tabela são convertidos em atributos da classe).
A camada DAO geralmente não fornece recursos dessa natureza, mas é útil para assumir como intermediária entre a aplicação e o banco de dados, ou seja, receber os dados, validá-los, gerar instruções SQL e garantir a persistências dos dados através de transações.

 

Até a próxima, leitores!
Abraço!


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

11 comentários

  1. Olá, André.
    Como pode perceber estou me dedicando a leitura dos artigos.
    Tem sido bastante úteis, principalmente eu tendo a intenção de remodelar tanto BD como Aplicativo.
    Não comentei antes mas meu filho também é do ramo, mas se dedica a Web, ainda ñ li o seu artigo sobre ‘MVC’, mas ‘discutindo’ com ele disse que uso o conceito, as regras de negocio estão no datamobile, o controller no aplicativo e o view nos relatórios e resultados de pesquisa.
    Estou muito errado, quase lá ou nada a ver?
    Obs: comecei com ‘Basic’ depois ‘dbase'(pascal) agora ‘Delphi’, tudo diferente, mas mesmo no ‘basic’ que é programação linear existia as subrotinas, no ‘dbase’ procedures, agora função, procedure, classe e tudo mais, como saber qual dos melhores métodos para programação daqui pra frente.?
    Nunca penso no hoje mas pros próximos 5 anos.
    Obrigado pela atenção.

    1. Olá, Gerson!
      Essa questão das técnicas para programação gera muito discussões, então acredito que não há uma resposta exata. Porém, com base no que eu já trabalhei, eu diria que a Orientação a Objetos e as disciplinas da Engenharia de Software (como SOLID, Clean Code e Design Patterns) são práticas extremamente relevantes para as atividades de codificação.
      A respeito do seu projeto, a arquitetura aparentemente está bem definida em camadas. Isso pode, sim, ser considerado como um modelo MVC, já que essas camadas têm as responsabilidades sugeridas pelo padrão. Parabéns!

      Abraço!

  2. Olá, André.

    Comentei antes sobre a minha falta de conhecimento das novas técnicas, até mesmo por não confiar em modismos, mas sou obrigado a aprender, o dificil e escolher a melhor opção mas vou observar as tecnicas que você citou.

    Obrigado.

  3. Boa Tarde, André.

    Tudo bem por ai?

    Quanto a arquitetura do MVC, entendi o conceito, estava quase lá, mas para aplicar só em um novo projeto.
    Já no P.O.O, acho que sempre tentei fazer algo parecido usando procedures e funções. Como sempre trabalhei direto do BD, em poucos casos fiz uma tela de entrada (acho que visão) para validar e persistir os dados. Aí começam as duvidas, tenho que validar nas classes (controle ou modelagem) e persistir no DAO?
    Me aprofundando nessa matéria, consegui perceber duas vantagens, a diminuição do uso de variáveis e a validação dos dados antes de persistir, mas só quando não escreve direto no DB. Até acho que escrever direto na tabela não é bom, embora mais rápido. Mas lembrando de alguns dos seus comentários, com muitos usuários simultâneos, não pode trabalhar direto na base porque dá erro (por isso separei nas mais acessadas).
    Vou continuar lendo os artigos e procurando mais detalhes, mas só soube o que procurar aqui.

    Obrigado.

    1. Olá, Gerson. Tudo bem!
      Realmente levaria um tempo para migrar um projeto já consolidado para uma arquitetura MVC. Talvez a melhor alternativa é refazê-lo do zero.
      Programação Orientada a Objetos vai além de procedures e functions, e envolve quatro pilares principais: Abstração (para modelagem de classes), Polimorfismo (para comportamento em chamadas de métodos), Herança (para criar novas classes a partir de classes já existentes) e Encapsulamento (controle de acesso aos atributos de uma classe). Fazer uso desses quatro pilares abre oportunidades para definir uma arquitetura flexível, estruturada e expansível de um projeto, permitindo, inclusive, a aplicação do MVC.

      Só não entendi muito bem sobre a escrita “direto na tabela”, Gerson. Poderia explicar melhor?
      Abraço!

  4. Olá, André.

    Estou tentando aprender os termos usados, por isso usei uma descrição do que entendi e associei, as descrições que você colocou agora já me ajudaram a associar melhor.
    Para facilitar o que quis dizer com escrever direto na tabela ou BD, é que uso o BDTables, e na edição dos cadastros, o DBEdit. Só no cadastro de produtos uso uma tabela local e depois gravo (persisto) no BD. Hoje sei que está errado, mas comecei com Paradox mono usuário e migrei para Interbase. Na maioria das outras operações uso stored procedures, tipo, gravar os dados de um cliente em um pedido ou NF-e e os itens num pedido. Muitas vezes uma nota é resultado da soma de vários pedidos, mais de 100 itens, então só envio o nº da referência e tudo é feito no BD sem tráfego de rede. Como sempre, já estendi o comentário, mas é usar o DBEdit direto na tabela do BD.
    MVC está fácil, mas POO, acho que entendi, vou explicar a dúvida: crio uma classe “pessoa” e as classes “cliente”, “fornecedor” e “usuário” herdam os campos comuns. Em outra “endereço” incluo ela na classe “pessoa”, assim as “subclasses” vão herdar os atributos, certo?
    Vou usar elas nos cadastros iniciais, pedidos de compra e venda, notas fiscais, faturamento, mas, se eu criar uma tabela “pessoas” e “endereços”, referenciadas pelo “cep”, e criar uma stored procedure que informando o ID da pessoa e onde será aplicado, pra que serviriam as classes? Só pra validar as informações?
    Acho que neste exemplo apliquei abstração, polimorfismo e herança. Criar as duas estruturas não seria uma redundância?
    Detalhar o relacionamento das tabelas no BD e a stored procedure facilitaria o entendimento da minha dúvida, mas estenderia muito.
    No seu último artigo, muito bom por acaso, nos referenciou como “mais que artistas”, e concordo plenamente (sempre pensei assim). A busca pela inovação tecnológica, funcionalidade, beleza e clareza da estrutura do código é fundamental.
    Por isso continuo estudando, compartilhando dúvidas e conhecimento. Nossa “Classe” só melhora com o compartilhamento de conhecimento, afinal a internet foi criada para isso.

    Abraço e sucesso!!

    1. Olá, Gerson!
      O exemplo da classe “Pessoa” é clássico no cenário de Programação Orientada a Objetos. Por exemplo, vamos supor que a aplicação irá trabalhar com Pessoas Físicas e Pessoas Jurídicas. Esses dois tipos de pessoas compartilham vários atributos em comum, como ID, Nome, Documento (CPF ou CNPJ), Endereço, Bairro, Cidade, UF, etc. Sendo assim, criamos a classe “Pessoa”, declarando estes atributos em comum, e depois herdamos a classe “Pessoa Física” e “Pessoa Jurídica”, declarando atributos mais específicos, como, por exemplo, a Razão Social para pessoa jurídica. Só aqui já alcançamos dois pilares: abstração e herança. Não será necessário duplicar os atributos em ambas as classes, pois ela já estará contida na classe base.
      Porém, sabemos que o documento é diferente para as duas classes. CPF é para pessoa física e CNPJ é para pessoa jurídica. É aqui que entra o polimorfismo. A classe “Pessoa” (classe base) terá um método chamado “ValidarDocumento”, mas quem irá implementá-lo são as classes filhas. A classe “Pessoa Física” irá validar o CPF, enquanto a “Pessoa Jurídica” irá validar o CNPJ. Observe que existirá apenas uma declaração de método, mas com implementações diferentes.
      A respeito do encapsulamento, recomendo a leitura de um artigo que escrevi no início de 2014, disponível neste link.

      Abraço!

  5. Olá, André, Boa noite.
    Já tinha lido a matéria, aliás, li quase todas, mas agora com melhor entendimento ficou mais claro.
    O que você achou da explicação do “escrever direto na tabela”? Acho que usei o termo errado, mas assim que vejo o método.

    Abraço!

    1. Olá, Gerson, tudo bem?
      Bom, essa questão de “escrever direto na tabela”, ou seja, utilizar componentes DBWare (como DBEdits) é um dilema entre desenvolvedores Delphi e foi uma das perguntas que respondi no FAQ 7. Eu, particularmente, prefiro implementar algo mais dinâmico, sem utilizar DBEdits. Procuro modelar minhas próprias classes para ter um controle pleno do tratamento de dados e da persistência no banco. Mas, claro, isso é uma preferência de cada desenvolvedor.

      Abraço!

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.