Afinal, o que é uma Entidade ?
Antes de mais nada, não vou começar falando de SQL como todo mundo por ai faz [ copiando trechos da Wikipedia ]. Se você está lendo meu blog, então vc sabe o que é SQL, sabe para que serve, e até provavelmente já trabalha com essa linguagem. Okay, vamos prosseguir.
Um conceito importante e interessante, mas que é fatalmente sonegado aos programadores, é o conceito de entidade [Basta tentar pesquisar por este termo, e notar como é escasso o conteúdo].
O resultado, são sistemas mal modelados, não normalizados, em que a aplicação tenta resolver diversos problemas da estrutura. 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…
E ai, 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 certo ? 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 ali de cima, no senso comum, 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.
Talvez esteja confuso até aqui, mas 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;
Até aqui bem simples. 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 é adicionarmos essas informações à entidade usuario, 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 ```
[<img src="/wp-content/uploads/2011/03/tab.png" alt="" title="tab" width="609" height="120" class="aligncenter size-full wp-image-394" srcset="/wp-content/uploads/2011/03/tab.png 609w, /wp-content/uploads/2011/03/tab-300x59.png 300w" sizes="(max-width: 609px) 100vw, 609px" />](/wp-content/uploads/2011/03/tab.png)
Porém, 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, o cara resolver incluir o Pager (ainda usam isso? hahauhaua), ou Nextel do camarada ?
Nesta hora, deveria começar a ficar claro que essa expansão, clama por uma nova entidade na nossa modelagem.
``` sql
ALTER TABLE `usuario` DROP `telefone` , DROP `celular` ;
Estrutura da nova entidade:
Dados cadastrados:
Portanto, se precisamos de mais formas de contato, como o Nextel, basta adicionarmos 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. Fazemos 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:
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.
data de nascimento, cidade natal e estado civil, cabem muito bem na entidade usuario.
Já o email, podemos colocar na entidade contato, concorda ?
Se lá pra frente, 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. Maior complexidade do modelo, queda de performance(afinal, agora consultamos 3 tabelas, e não apenas uma), em contrapartida com 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');