Seções iMasters
Desenvolvimento + SQL Server

Afinal, o que é uma entidade?

Não vou começar falando de SQL, como geralmente é feito, mesmo que copiando trechos da Wikipedia.

Vejamos um conceito importante e interessante, mas que é fatalmente sonegado aos programadores, é o conceito de entidade. Basta tentar pesquisar por este termo, e notar como o conteúdo é escasso.

Talvez por isso, os resultados são sistemas mal modelados, não normalizados, em que a aplicação tenta resolver diversos problemas da estrutura, e onde qualquer novo requisito, gera um grande transtorno, pois a análise para criação do modelo, não foi feita corretamente, de modo a deixar a estrutura robusta e expansível.

Um exercício rápido

  • Volante, Pára-choque, Retrovisores, Câmbio, Chassis, Rodas, Motor, Portas…

O que lhe veio a mente? Qual objeto do nosso mundo agrega essas partes que citei? Espero que a sua resposta seja ‘um carro’. Faz parte do senso comum.

Mais uma vez

  • Galhos, Folhas, Raíz, Tronco, Copa, Calotas..

Uma árvore? Só as ‘calotas’ que parecem não estar no lugar correto, pois não combinam com os outros itens, e não conseguimos imaginar que as calotas, devam pertencer a nossa árvore.

Melhor mover as ‘calotas’ para o ‘carro’ lá de cima, para se encaixar melhor em uma normalidade aceitável.

Ao iniciar o levantamento de informações, o processo é mais ou menos parecido com esse. O carro, e a árvore são as nossas entidades e cada um dos itens que citei, são os atributos particulares dessas entidades. A idéia é saber a quem deve pertencer cada atributo, e sermos capazes de definirmos as entidades do nosso sistema.

Formalmente

  • Uma entidade possui atributos.
  • Os atributos são as características e não devem conter um grupo de informações.
  • Não existem entidades com menos de 2 atributos. Logo, cada entidade, é em si, um grupo de atributos.

Trazendo de forma livre para a nossa realidade, cada Entidade é uma tabela, e cada Atributo é cada uma das colunas dessas tabelas.

O ponto que quero levantar é a compreensão do conceito. Se tenho que fazer um cadastro de usuário, preciso pensar o que a entidade usuário significa para o meu sistema e o que preciso saber dela ou não.

    CREATE TABLE `test`.`usuario` (  
       `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , 
       `nome` VARCHAR( 50 ) NOT NULL 
    ) ENGINE = InnoDB; 

A nossa entidade usuario possui um `nome`, e um `id`, que é um identificador único desse objeto no nosso modelo.

Agora o cliente nos informa que ele precisa saber dos usuarios dele, pelo menos:

  • um telefone residencial, e
  • um celular.

Num primeiro momento, a nossa reação será adicionar essas informações à entidade usuário, pois o telefone e o celular pertencem respectivamente a cada usuário nosso.

    ALTER TABLE `usuario` ADD `telefone` VARCHAR( 14 ) NOT NULL ,  
    ADD `celular` VARCHAR( 14 ) NOT NULL  


Mas se nosso chefe vem e nos informa que agora ele precisa também do Telefone Comercial do nosso usuário e quem sabe talvez um Telefone de Contato? É nesse momento que o nosso modelo pode naufragar ou não.

Adicionar mais essas 2 colunas a tabela seria um erro no ponto de vista da modelagem de negócios, pois estaríamos novamente, subestimando a aplicação. E se lá pra frente, ele decidir incluir o Pager (ainda usam isso? hahaha), ou o id Nextel do usuário?

Nesta hora, deveria começar a ficar claro que essa expansão clama por uma nova entidade na nossa modelagem.

ALTER TABLE `usuario` DROP `telefone` , DROP `celular` ; 

Estrutura da nova entidade

Dados cadastrados:

Portanto, se precisamos de inserir mais formas de contato, basta adicionar um registro a essa tabela. E isso pode ser facilmente feito na nossa aplicação, sem a necessidade de alterarmos a estrutura do modelo.

    INSERT INTO `test`.`contato` (`id`, `nome`) VALUES (NULL, 'Nextel');  

A única questão não respondida ainda é como vincular os dados do usuário a esta nossa nova entidade. Faremos então outra tabela, já bem normalizada, da seguinte forma:

    CREATE TABLE `test`.`contato_usuario` (  
        `id_usuario` INT NOT NULL , 
        `id_contato` INT NOT NULL , 
        `descricao` VARCHAR( 70 ) NOT NULL 
    ) ENGINE = InnoDB; 

Essa nossa nova tabela será responsável por fazer a ligação entre as nossas entidades.

A relação entre as tabelas é evidente e o nosso JOIN para resgatar esses dados fica da seguinte forma:

    SELECT `usuario`.`id` AS `id_usuario` , `usuario`.`nome` AS `nome_usuario` ,  
      `contato`.`nome` AS `nome_contato` , `contato_usuario`.`descricao` 
        FROM `usuario` 
            INNER JOIN `contato_usuario` ON `usuario`.`id` = `contato_usuario`.`id_usuario` 
            INNER JOIN `contato` ON `contato`.`id` = `contato_usuario`.`id_contato` 

Saída:


Continuando, surgem novos atributos:

data de nascimento, cidade natal, email, estado civil..

Precisamos dividir esses atributos nas nossas entidades. A data de nascimento, a cidade natal e estado civil cabem muito bem na entidade usuário. Já o email, podemos colocar na entidade contato, concorda?

Se mais adiante precisarmos de um ‘email_secundario’, para proteção do sistema, onde o usuário poderá resgatar a senha dele na nossa aplicação, bastará novamente, inserirmos um registro na entidade contato, sem a menor alteração do modelo que criamos.

Esse particionamento que fizemos tem o seu custo. A maior complexidade do modelo, a queda de performance (afinal, agora consultamos 3 tabelas e não apenas uma). E em contrapartida, temos os ganhos que essa modelagem trouxe a estrutura da nossa aplicação.

Analise bem os requisitos do seu sistema antes de implementá-lo. Não tome todo e qualquer tutorial como lei ou verdade absoluta.

Dump completo do SQL usado:

    -- phpMyAdmin SQL Dump  
    -- version 3.3.8.1 
    -- http://www.phpmyadmin.net 
    -- 
    -- Servidor: localhost 
    -- Tempo de Geração: Mar 29, 2011 as 02:54 AM 
    -- Versão do Servidor: 5.5.8 
    -- Versão do PHP: 5.3.4 
     
    SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; 
     
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 
    /*!40101 SET NAMES utf8 */; 
     
    -- 
    -- Banco de Dados: `test` 
    -- 
     
    -- -------------------------------------------------------- 
     
    -- 
    -- Estrutura da tabela `contato` 
    -- 
     
    CREATE TABLE IF NOT EXISTS `contato` ( 
      `id` int(11) NOT NULL AUTO_INCREMENT, 
      `nome` varchar(40) NOT NULL, 
      PRIMARY KEY (`id`) 
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; 
     
    -- 
    -- Extraindo dados da tabela `contato` 
    -- 
     
    INSERT INTO `contato` (`id`, `nome`) VALUES 
    (1, 'Telefone Residencial'), 
    (2, 'Telefone Comercial'), 
    (3, 'Celular'), 
    (4, 'Nextel'); 
     
    -- -------------------------------------------------------- 
     
    -- 
    -- Estrutura da tabela `contato_usuario` 
    -- 
     
    CREATE TABLE IF NOT EXISTS `contato_usuario` ( 
      `id_usuario` int(11) NOT NULL, 
      `id_contato` int(11) NOT NULL, 
      `descricao` varchar(70) NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 
     
    -- 
    -- Extraindo dados da tabela `contato_usuario` 
    -- 
     
    INSERT INTO `contato_usuario` (`id_usuario`, `id_contato`, `descricao`) VALUES 
    (1, 2, '(11) 1234-5678'), 
    (1, 4, '55*11*1111'), 
    (2, 1, '(12) 4321-8765'), 
    (2, 2, '(11) 8765-4321'), 
    (2, 4, '55*22*2222'); 
     
    -- -------------------------------------------------------- 
     
    -- 
    -- Estrutura da tabela `usuario` 
    -- 
     
    CREATE TABLE IF NOT EXISTS `usuario` ( 
      `id` int(11) NOT NULL AUTO_INCREMENT, 
      `nome` varchar(50) NOT NULL, 
      PRIMARY KEY (`id`) 
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ; 
     
    -- 
    -- Extraindo dados da tabela `usuario` 
    -- 
     
    INSERT INTO `usuario` (`id`, `nome`) VALUES 
    (1, 'Bruno'), 
    (2, 'Silveira'); 
Mensagem do anunciante:

Torne-se um Parceiro de Software Intel®. Filie-se ao Intel® Developer Zone. Intel®Developer Zone

Comente também

19 Comentários

João Artur Manjabosco

ótimo artigo, parabéns!!! ficou mais fácil de entender o que é uma entidade. show.

Wagner

excelente artigo Bruno realmente muita gente erra nisso.

Guilherme Mateus

olá Willian, boa tarde! ainda nesse conceito de que uma entidade é uma tabela no sistema e até por questões de padronização de nomenclatura, é correto eu nomear minhas tabelas do banco do mesmo jeito que nomeio minhas entidades? por exemplo: por padrão em UML (pelo menos como aprendi, rss) nomeia-se uma entidade no singular e com a primeira letra dela em maiúscula (ex: Cliente). faço isso também com todas as minhas tabelas para manter um padrão mas a pergunta é se isso é correto pois já procurei em vários lugares e o que vi é que não há um consenso. ahhh, e muuuito bom este seu post! :)

    William Bruno

    Opa! Boa Tarde Guilherme !

    Sim cara, é bem por ai. O meu ‘saldo final’, depois de tudo oque li, estudei e pratiquei desenvolvendo sistemas é:
    -> entidades no singular
    -> underline para separar (camelCase, não é bacana, por conta de alguns bugs que conhecemos[diferenças entre SOs]), logo isso, me faz preferir escrever tudo em minusculo.

    No banco, prefiro usar sempre letra minuscula, e até começar com minúscula. Já para classes, se aplica a primeira em Maiúscula, e UpperCamelCase

    vlw pelo apoio

    William Oliveira Ferreira

    achei que por questoes de seguranca, voce indicaria algum prefixo ou sufixo aos nomes das entidades

Lucas Pelegrino

Muito bom Bruno. O tutorial também se encaixa no conceito de orientação a objetos, na verdade, foi a primeira coisa que pensei quando li.Esse tipo de abstração deve ser feito, em minha opnião, na modelagem do db e no desenvolvimento, a organização é muito maior.

Paranbéns.

    William Bruno

    Obrigado Lucas, é bem por ai mesmo.

    Esse ‘pensamento’ pode ser aplicado na construção das nossas classes sim.
    Estariamos nos aproximando de um ORM.

Rodrigo

Boa matéria e bom assunto, Parabéns novamente.

Bruno Guimarães Carneiro

A tabela contato_usuario é uma entidade?

Um usuario possui um ou mais contatos. A entidade usuario possui outras entidades, não apenas atributos.

Bruno Guimarães Carneiro

Na verdade, eu estava falando sobre o domínio sem atentar para a forma como você implementou.

O que eu falei não se encaixa na forma como você implementou. Na forma como você implementou nenhum usuario possui um contato. Um usuario apenas possui uma relação com um ou mais usuarios e cada uma dessas relações especifica um atributo descrição que pode ser o número do telefone, o email, ou qualquer coisa. Não creio que seja uma boa solução pois vc pode fazer um relacionamento entre um usuario e um telefone e colocar como descrição (27) 9999-9999, por exemplo.

    William Bruno

    Oi Bruno, a implementação que fiz, foi a mais robusta possível.

    Sim, de fato é exatamente isso que eu faço.
    Crio um relacionamento entre um usuário e um telefone, e coloco a descrição o número do telefone.

    A idéia foi explicitar o conceito, e para isso usei um caso bem absurdo, porém corriqueiro. Melhor do que ficar falando sobre Gatos, Feijoadas, ou coisas que não se aplicam ao nosso dia-a-dia, certo? =)

William Bruno

Obrigado pelo apoio João, Wagner e Rodrigo

Franklin

Creio que desta forma a queda de performance pode ser equilibrada fazendo o uso correto de visões e funções.

Daniel Antunes

Uma coisa simples, mas que muita gente ainda comete o pecado de errar…

Ótimo artigo.

Bruno Giannella de Melo

” Uma coisa simples, mas que muita gente ainda comete o pecado de errar… ” exatamente como o Daniel falou, mais é importante mostrar isso porque muita gente ainda acaba comentendo falhas nesse aspecto.

Parabéns.

    William Bruno

    Exato Daniel e Bruno.

    Falta muita (in)formação básica em vários programadores de hoje em dia. Acham que ‘resolver é resolver’, e que ‘tanto faz a forma que será feito’.

Amylee

Mei a explicação =]

Cristhiane

Muito Boa a explicação…Um Modo simples e fácil de se entender… William Bruno..*-*

Qual a sua opinião?