Tradução Angelo Giusepe Meira da Costa (angico)

Propaganda
Tradução
Angelo Giusepe Meira da Costa (angico)
Do original:
Entity Framework 4 – In Action
Copyright©
© 2012 Editora Ciência Moderna
© ©!"#
$
% & ''
* + ,- .
&/0
!
Editor: Paulo André P. Marques
Produtora Editorial: Laura Santos Souza
Diagramação: Carlos Arthur Candal
Tradução: Angelo Giuseppe Meira Costa (angico)
Capa: Daniel Jara (Baseada na Original)
Assistente Editorial: Amanda Lima da Costa
Várias Marcas Registradas aparecem no decorrer deste livro. Mais do que
simplesmente listar esses nomes e informar quem possui seus direitos de exploração, ou
ainda imprimir os logotipos das mesmas, o editor declara estar utilizando tais nomes
apenas para fins editoriais, em benefício exclusivo do dono da Marca Registrada, sem
intenção de infringir as regras de sua utilização. Qualquer semelhança em nomes
próprios e acontecimentos será mera coincidência.
FICHA CATALOGRÁFICA
MOSTARDA, Stefano. SANCTIS, Marco de. BOCHICCHIO, Daniele.
Rio de Janeiro: Editora Ciência Moderna Ltda., 2012.
1. Informática; 2. Linguagem de programação. 3. Processamento de dados
I — Título
ISBN: 978-85-399-0302-3
CDD 001.642
005.133
005.7
!"#$%#&'%#
(!)"'*""#'&"+,!)"'*""#'&-$
&.!
/
0 111
0
#-+'"
Apresentação
Eu passei muito tempo, aqui, na Microsoft, pensando em complexidade –
e me fazendo muitas perguntas. Eu aposto que você faz o mesmo.
Quando projetamos código, nós nos fazemos perguntas como estas: Posso
tornar esse código mais legível? Posso escrever este laço com menos linhas?
Posso transferir o comportamento para uma classe separada? Posso arquitetar
HVWHVLVWHPDGHPRGRTXHHOH¿TXHPDLVFRHVR"
Quando projetamos interfaces de usuário, nós fazemos perguntas similares: Será que estamos pedindo ao usuário para tomar decisões demais? Arranjamos esta UI da maneira mais clara possível? Podemos tornar os estados de
erro mais claros e mais fáceis de evitar?
Quando projetamos sistemas, nós fazemos outras perguntas: Quantos conceitos o usuário deve aprender? Esses conceitos são mapeados para coisas que
o usuário conhece e se preocupa? Será que tudo se junta de uma forma clara,
sensata e consistente?
Eu penso muito nessas coisas. Mas, primeiro, eu gostaria de responder a
outra pergunta que muitas vezes eu me faço: quão complicada é, exatamente, a
Estrutura de Entidades? A resposta é que isso depende do que você quer fazer
com ela.
Para ver o quanto a Estrutura de Entidades é simples, vamos gastar cinco
minutos fazendo-a passar por uma simples série de etapas. Você precisará do
Visual Studio 2010 (as edições Express funcionarão) e do SQL Server (novamente, as edições Express funcionarão bem). No SQL Server, crie uma base
de dados chamada “EntityFrameworkIsSimple”.
1. Inicie o Visual Studio 2010;
2. No menu View, selecione Server Explorer;
3. No Server Explorer, adicione uma nova conexão a sua base de dados
EntityFrameworkIsSimple;
4. Crie um novo projeto Console Application, e nomeie-o
EntityFrameworkIsSimple;
5. Clique com o botão direito no projeto e selecione Add > New Item.
No diálogo Add New Item, selecione ADO.NET Entity Data Model;
6. Clique em Add;
7. No Assistente Entity Data Model que é apresentado, selecione Empty
IV - Entity Framework 4 - A Estrutura de Entidades - em Ação
Model e clique em Finish;
8. O designer de entidades aparecerá. Clique com o botão direito nele e
selecione Add > Entity;
9. No diálogo Add Entity, ajuste o nome da entidade para Person. Isto
criará automaticamente o conjunto de entidades People (o conjunto é
o nome da coleção à qual você adicionará novas instâncias da classe Person);
10. Clique em OK;
11. Uma nova entidade aparecerá. Clique com o botão direito na barra
Properties, dentro dela, e selecione Add > Scalar Property (ou simplesmente clique na tecla Insert);
12. Renomeie a nova propriedade para FirstName;
13. Faça isso de novo, criando uma nova propriedade chamada LastName;
14. Adicione uma outra entidade e chame-a Book;
15. Para esta nova entidade, adicione uma propriedade chamada Title;
16. Clique com o botão direito no texto “Person”, na entidade Person, e
selecione Add > Association;
17. No diálogo Add Association, altere Multiplicity, no lado Person para
* (Many), e altere o valor de Navigation Property, à direita, de
Person para Authors;
18. Clique em OK;
19. Neste ponto, seu modelo deverá se parecer com este:
20. Agora, clique com o botão direito numa área vazia do designer e selecione Generate Database from Model;
21. No Assistente Generate Database que aparecerá, forneça uma conexão
para sua base de dados. Como nós adicionamos uma conexão para a
base de dados no início deste passo a passo, ele deverá aparecer na
lista drop-down de conexões disponíveis;
22. Clique em Next;
23. A DDL para uma base de dados para guardar seu modelo será mostrada. Clique em Finish;
Apresentação - V
24. No editor de T-SQL que aparecerá, clique com botão direito e selecione Execute SQL. Forneça as informações de sua base de dados
local, quando solicitado a se conectar.
É isso aí! Temos um modelo. Temos código. Temos uma base de dados.
7HPRVDWpXPDVWULQJGHFRQH[mRHP$SS&RQ¿JTXHRGHVLJQHUFULDHPDQtém para você.
Vamos levar este modelo para um test drive. Vamos nomear o modelo:
1. No designer, clique com o botão direito numa área vazia da tela e
selecione Properties;
2. Na janela Properties, localize a propriedade chamada Entity Container
Name e altere seu valor para SimpleModel;
3. Em Program.cs, digite o seguinte código no corpo da função Main:
// Cria e escreve nossos dados de amostra
using (var context = new SimpleModel()) {
var person1 = new Person() { FirstName = “Stefano”, LastName=”Mostarda” };
var person2 = new Person() { FirstName = “Marco”, LastName=”De Sanctis” };
var person3 = new Person() { FirstName = “Daniele”, LastName=”Bochicchio” };
var book = new Book() { Title = “Microsoft Entity Framework In Action”};
book.Authors.Add(person1);
book.Authors.Add(person2);
book.Authors.Add(person3);
context.People.AddObject(person1);
context.People.AddObject(person2);
context.People.AddObject(person3);
context.Books.AddObject(book);
context.SaveChanges();
}
// Consulta nossos dados de amostra
using (var context = new SimpleModel()) {
var book = context.Books.Include(“Authors”).First();
Console.Out.WriteLine(“The authors ‘{0}’ are:”, book.Title);
VI - Entity Framework 4 - A Estrutura de Entidades - em Ação
foreach(Person author in book.Authors) {
Console.Out.WriteLine(“ - {0}
{1}”, author.FirstName, author.LastName);
}
}
Console.Read();
4. Compile e rode este código. Você deverá ver a seguinte saída:
Como você pode ver, nós criamos um sistema que emite consultas e atualiza três tabelas diferentes. E nem uma única sentença join à vista!
Claro que, no mundo real, temos muitas outras preocupações: Como ligamos esses tipos a elementos de UI? Como os enviamos e atualizamos através
de camadas de aplicativos distribuídos? Como tratamos concorrência, consultas dinâmicas, e procedimentos armazenados? Embora a Estrutura de Entidades possa ser simples, para começar, o mundo real não é simples, e a Estrutura
de Entidades tem uma série de funcionalidades para lidar com situações do
mundo real.
Incluir um exemplo como este pode não ser padrão para prefácio de um
OLYURPDVHX¿]LVVRSDUDPRVWUDUFRPRpIiFLOFRPHoDUFRPD(VWUXWXUDGH
Entidades, e também para mostrar onde este livro entra. Entity Framework 4
– A Estrutura de Entidades - em Ação levará você do tratamento de transações
ao entendimento de como lidar com problemas de desempenho e usar ESQL
para escrever consultas dinâmicas. E ele responderá todas as suas perguntas,
ao longo do caminho – mesmo as que você não sabia que tinha!
Espero ver o que você fará com a Estrutura de Entidades e ouvir o que
você quer que a gente faça em seguida. Os autores estão tão empolgados
quanto eu para mostrar o que está por vir, no futuro!
Noam Ben-Ami
Gerente de Programas
Equipe da Estrutura de Entidades, Microsoft
Prefácio
Conseguimos! Escrevemos um livro sobre a Estrutura de Entidades!
Não é nosso primeiro livro, mas é o primeiro escrito em inglês e distribuído
PXQGLDOPHQWH)RLXPJUDQGHGHVD¿RPDVWHUDRSRUWXQLGDGHGHGLVVHPLQDU
o conhecimento da Estrutura de Entidades fez valer o esforço. A Estrutura
de Entidades é uma excelente ferramenta que acelera o desenvolvimento de
FyGLJRGHDFHVVRGHGDGRVHTXHSRGHSRXSDUDYRFrGLDVHGLDVGHFRGL¿FDomR
6DEHPRVTXHFRGL¿FDUpRQRVVRWUDEDOKRPDVYRFrQmRSUHIHULULDVHUPDLV
produtivo ao mesmo tempo que escrevesse menos e melhor código?
A Estrutura de Entidades é uma ótima ferramenta de O/RM que está
LQWHJUDGDQD(VWUXWXUD1(7RTXHVLJQL¿FDTXHQmRVyHODpJUDWXLWDFRPR
também é mantida e melhorada a cada nova liberação da Estrutura .NET. O
resultado é que ela é uma excelente plataforma, hoje, e que amanhã será um
destaque que provavelmente reinará sobre todas as outras plataformas de O/
RM.
Quando começamos a planejar este livro, tínhamos uma clara ideia em
mente: não queríamos criar um livro de referência; queríamos criar um prático. Queríamos que você lesse a respeito de problemas do mundo real e
aprendesse soluções do mundo real. É por isso que desenvolvemos um exemplo e o melhoramos ao longo de todo o livro, evitando armadilhas comuns e
resolvendo problemas que você enfrentaria no trabalho.
Este é um livro que nós sentimos que faltava entre os que estão disponíveis. Você não encontrará uma descrição detalhada de todas as classes e
propriedades aqui, mas aprenderá a melhor maneira de usá-las e a combinar
funcionalidades para tirar o máximo proveito da Estrutura de Entidades.
Demorou muito a escrita deste livro, mas, agora que ele está em suas mãos,
podemos parar de desperdiçar noites intermináveis na frente de nossos moniWRUHVH¿QDOPHQWHVHQWDUHSDVVDUPDLVWHPSRFRPQRVVDVIDPtOLDV$JRUDp
sua vez. Aproveite a leitura, arregace as mangas, e divirta-se.
Agradecimentos
Não podemos contar todas as pessoas que contribuíram para este livro,
FDGDXPDDMXGDQGRDPHOKRUDURSURGXWR¿QDO7RGDVHODVPHUHFHPXPFDORroso obrigado. Embora não possamos nomear todos, aqui, nós gostaríamos de
fazer um agradecimento especial às seguintes pessoas que foram particularmente úteis:
Sebastian Stirling, nosso editor de desenvolvimento, na Manning – Sebastian trabalhou conosco desde o princípio, e magistralmente transformou um
punhado de palavras e imagens num livro atraente. Muito obrigado.
Elisa Flasko, Gerente de Programas da equipe da Estrutura de Entidades, na Microsoft – Elisa forneceu informações valiosas e direcionava nossas
questões para a pessoa certa, quando não tinha as respostas. Sem ela, este livro
não seria tão profundo. Muito obrigado.
Noam Ben-Ami, Gerente de Programas da equipe da Estrutura de Entidades, na Microsoft – Noam nos apontou para as soluções corretas de muitos
problemas, e foi especialmente útil quando estivemos escrevendo o capítulo
13. Ele também escreveu a apresentação de nosso livro. Muito obrigado.
Alessandro Gallo, ASP Insider, consultor e autor principal do ASP.NET
Ajax in Action, da Manning – Alessandro não contribuiu para o conteúdo deste
livro, mas foi a fagulha que deu partida a tudo. Muito obrigado.
Muitas pessoas, na Manning, trabalharam duro para tornar este livro
possível. Antes de mais nada, um especial obrigado a Michael Stephens e
Marjan Bace por acreditarem em nós. Outros que contribuíram foram Karen
Tegtmeyer, Mary Piergies, Maureen Spencer, Andy Carroll, Dottie Marsico,
Tiffany Taylor, Susan Harkins, Janet Vail e Cynthia Kane.
Nossos revisores merecem menção especial – suas sugestões foram valiosas. Agradecemos a Jonas Bandi, David Barkol, Timothy Binkley-Jones, Margriet Bruggeman, Nikander Bruggeman, Gustavo Cavalcanti, Dave Corun,
Freedom Dumlao, Rob Eisenberg, Marc Gravell, Berndt Hamboeck, Jason
Jung, Lester Lobo, Darren Neimke, Braj Panda, Christian Siegers, Andrew
Seimer, Alex Thissen, Dennis van der Stelt e Frank Wang. Gostaríamos de
agradecer, também, a Deepak Vohra, nosso revisor técnico, pelo excelente
WUDEDOKRGHUHYLVmRGRPDQXVFULWR¿QDOGXUDQWHDSURGXomR
3RU¿PPDVQmRPHQRVLPSRUWDQWHREULJDGRDYRFrFDUROHLWRUSRUVXD
fé em nosso livro. Esperamos que ele ajude em seu trabalho diário, e que ele
X - Entity Framework 4 - A Estrutura de Entidades - em Ação
encoraje você a se apaixonar pelo mundo dos O/RMs.
Além das pessoas que já mencionamos, há outras que são importantes em
nossas vidas. Mesmo que elas não tenham contribuído para o livro, contribuíram para nos manter na linha, durante o processo de escrita. Nós as reconhecemos abaixo.
STEFANO MOSTARDA
“Gostaria de agradecer a minha mulher, Sara, pelo seu apoio e paciência,
!"
Gabriele, Gianni e Riccardo. É claro que eu não posso deixar de mencionar o
Filippo, que já comprou uma cópia do livro. E um muito obrigado a William
e Annalisa pela sua amizade e valioso apoio.
#
$%#&
!'
MARCO DE SANCTIS
“Meu muito obrigado a Stefano e Daniele. Foi um privilégio trabalhar
com gente tão inteligente e divertida. E obrigado a toda a equipe da ASPItalia. Sinto-me orgulhoso de ser parte dela.
Um agradecimento especial a minha família, e a Barbara, pelo seu apoio
(
)('
DANIELE BOCHICCHIO
“Gostaria de agradecer à minha mulher, Noemi, pelo seu apoio e paciên
#*
a meus pais, por me permitirem brincar com computadores quando eu era
criança, e à minha família por me apoiar.
Um obrigado especial a Stefano pela oportunidade de ajudar neste livro.
E obrigado a ambos, Stefano e Marco, por compartilharem sua paixão pela
++
/
(%'
Sobre este Livro
A Estrutura de Entidades é a ferramenta recomendada pela Microsoft
para leitura e persistência de dados numa base de dados relacionais. Com este
VRIWZDUHD0LFURVRIWHQWURXQRPHUFDGRGH250FRPXPSURGXWRFRQ¿iYHO
TXHIDFLOLWDVLJQL¿FDWLYDPHQWHRGHVHQYROYLPHQWRGHDFHVVRDGDGRV
Este livro levará você do nível de aprendiz ao de mestre na tecnologia da
Estrutura de Entidades. Você pode pensar nele como um passeio guiado pelas
funcionalidades e melhores práticas da Estrutura de Entidades. Quando tiver
terminado de ler o Entity Framework 4 – Estrutura de Entidades- em Ação,
YRFrVHUiFDSD]GHFRQ¿DQWHPHQWHSURMHWDUGHVHQYROYHUHGLVWULEXLUDSOLFDWLvos que se baseiam na Estrutura de Entidades para persistir dados funcionais.
Quem deve ler este livro?
Este livro foi escrito para todos os desenvolvedores da Estrutura de Entidades, não importando se você desenvolve pequenos aplicativos domésticos,
ou os maiores sistemas empresariais. Tudo, desde aplicativos de bibliotecas
domésticas de DVDs até soluções de e-commerce que interagem com muitos
VLVWHPDVKHWHURJrQHRVHDUPD]HQDPPRQWHVGHLQIRUPDo}HVSRGHVHEHQH¿ciar da Estrutura de Entidades, e este livro mostrará como.
Roteiro
Este livro guiará você pela criação de um aplicativo a partir do zero, e
mostrará como manter-se melhorando-o com várias funcionalidades da Estrutura de Entidades. Esta jornada pela Estrutura de Entidades cobrirá todas as
funcionalidades da Estrutura, ao longo do curso de dezenove capítulos, agrupados em quatro partes.
Na parte 1, nós apresentamos os fundamentos do padrão O/RM e mostraremos os fundamentos da Estrutura de Entidades, à medida que criamos as
bases para um aplicativo.
O capítulo 1 fornece uma visão geral de alto nível do padrão O/RM e dos
FRPSRQHQWHVGD(VWUXWXUDGH(QWLGDGHV$R¿QDOGHVWHFDStWXORYRFrHQWHQGHUi
XII - Entity Framework 4 - A Estrutura de Entidades - em Ação
por que as ferramentas de O/RM são tão úteis e como a Estrutura de Entidades
realiza suas funções.
O capítulo 2 mostra como você pode criar um aplicativo a partir do zero,
e como persistir objetos na base de dados. Primeiro, você aprenderá duas
maneiras de projetar um aplicativo usando a Estrutura de Entidades. Depois,
quando o aplicativo estiver criado, você aprenderá a ler, manipular e persistir
GDGRV$R¿QDOGHVWHFDStWXORYRFrWHUiXPFODURHQWHQGLPHQWRGDVYDQWDJHQV
da adoção da Estrutura de Entidades.
Na parte 2 do livro, nós discutimos os principais blocos de construção da
Estrutura de Entidades em detalhes: mapeamento, consulta e persistência.
O capítulo 3 aborda os conceitos básicos de consulta. Aqui você aprenderá
sobre o principal componente que habilita a Estrutura de Entidades a trabalhar
com objetos. Você também descobrirá como a Estrutura de Entidades permite
que você escreva consultas contra o modelo que atingirão com sucesso a base
de dados.
O capítulo 4 foca a consulta com o LINQ para Entidades. Neste capítulo,
YRFrDSUHQGHUiD¿OWUDUDJUXSDUSURMHWDUHMXQWDUGDGRVXVDQGRDSULQFLSDOOLQJXDJHPGHFRQVXOWDVGD(VWUXWXUDGH(QWLGDGHV$R¿QDOGHVWHFDStWXORYRFr
será capaz de realizar qualquer tipo de consulta.
O capítulo 5 discute o mapeamento entre entidades do modelo e da base
de dados. Aqui você aprenderá a fazer isso visualmente com o designer, mas
YRFrWDPEpPDSUHQGHUiDPRGL¿FDUPDQXDOPHQWHRDUTXLYRGHPDSHDPHQWR
$R¿QDOGHVWHFDStWXORYRFrWHUiFRQKHFLPHQWRFRPSOHWRGRPHFDQLVPRGH
mapeamento da Estrutura de Entidades.
O capítulo 6 explora o ciclo de vida das entidades. Você aprenderá como
a Estrutura de Entidades trata as entidades, em que estado uma entidade pode
HVWDUFRPRPRGL¿FDURHVWDGRHFRPRRHVWDGRDIHWDDSHUVLVWrQFLDGHXPD
HQWLGDGH$R¿QDOGRFDStWXORYRFrVHUiFDSD]GHHVFUHYHUFyGLJRTXHSUHSDUD
seus objetos para persistência na base de dados.
O capítulo 7 discute a persistência de objetos na base de dados. No
capítulo 6 você aprendeu a preparar entidades para persistência; aqui, você
aprenderá realmente a salvá-las. Este assunto tem muitas complexidades e
armadilhas, especialmente onde entidades relacionadas estão envolvidas. Este
capítulo foca nesses problemas potenciais, de modo que você possa entendêORV H HYLWiORV$R ¿QDO GR FDStWXOR YRFr VHUi FDSD] GH SHUVLVWLU TXDOTXHU
entidade da maneira que precisar.
O capítulo 8 aborda as funcionalidades de concorrência e transação da
Estrutura de Entidades. Na primeira parte do capítulo, você será apresentado
ao conceito de concorrência e aos problemas que ele resolve quando dados
Sobre este Livro - XIII
são salvos na base de dados. Depois, você aprenderá como a Estrutura de
(QWLGDGHVSHUPLWHTXHYRFrJHUHQFLHIDFLOPHQWHDFRQFRUUrQFLD3RU¿PYRFr
aprenderá como a Estrutura de Entidades gerencia transações para persistir
múltiplas entidades, e como você pode estender o tempo de vida de uma transação para executar comandos personalizados.
A parte 3 do livro mostrará como tirar proveito das funcionalidades mais
avançadas da Estrutura de Entidades.
O capítulo 9 apresenta o SQL de Entidades. O SQL de Entidades é outra
linguagem de consultas da Estrutura de Entidades, e ainda é a mais poderoso
(embora menos atraente que o LINQ para Entidades).
Neste capítulo, tomaremos os exemplos do LINQ para Entidades do capítulo 4 e os reescreveremos no SQL de Entidades. Você poderá vê-los lado a
ODGR H HVFROKHU D DERUGDJHP TXH VHMD PDLV IiFLO SDUD YRFr$R ¿QDO GHVWH
capítulo, você terá um conhecimento completo de todas as técnicas de consulta que a Estrutura de Entidades oferece.
O capítulo 10 abrange os procedimentos armazenados. Aqui você vai
aprender como fazer com que a Estrutura de Entidades chame procedimentos
armazenados para consultar e atualizar entidades, em vez de fazê-la gerar SQL
SDUDYRFr$R¿QDOGHVWHFDStWXORYRFrVHUiFDSD]GHFULDUVHXSUySULRFRQjunto de procedimentos armazenados e fazer com que a Estrutura de Entidades
RVLQYRTXHGHIRUPDTXHVHX'%$¿TXHIHOL]
O capítulo 11 discute vistas e funções embutidas em mapeamento. Você
verá como criar vistas internas que podem ser facilmente consultadas, e como
criar funções que podem ser reutilizadas quando consultando com o LINQ
SDUD(QWLGDGHVHR64/GH(QWLGDGHV$R¿QDOGHVWHFDStWXORYRFrVHUiFDSD]
de escrever consultas que são fáceis de manter e reutilizar.
O capítulo 12 discute como recuperar informações de mapeamento. O
capítulo 5 explica como mapear suas classes de modelo para tabelas e vistas
da base de dados; neste capítulo, você aprenderá a recuperar esta informação de mapeamento. Você também verá alguns exemplos do mundo real que
demonstrarão por que esta técnica é valiosa. Depois de terminar este capítulo, você será capaz de escrever código genérico poderoso que pega dados de
arquivos de mapeamento.
O capítulo 13 cobre a geração de código. Aqui, você descobrirá como a
Estrutura de Entidades é integrada ao Visual Studio, e como essa integração
permite que você crie código e até mesmo gere scripts de base de dados a
partir de informações de mapeamento. Você também descobrirá como personalizar o designer da Estrutura de Entidades dentro do Visual Studio. Depois
de terminar este capítulo, você será capaz de personalizar completamente o
XIV - Entity Framework 4 - A Estrutura de Entidades - em Ação
GHVLJQHUDGLFLRQDQGRFRPSRUWDPHQWRVTXHVLPSOL¿FDPRGHVHQYROYLPHQWR
Na parte 4 do livro, nós mostraremos como usar melhor a Estrutura de
Entidades com diferentes tipos de aplicativos: aplicativos Windows, web e de
serviços web.
O capítulo 14 discute o design de aplicativos. Você aprenderá o clássico
padrão de três camadas e depois partirá para o padrão de Modelo de Domínio.
3RU¿PYRFrOHUiVREUHRIDPRVRSDGUmRGH5HSRVLWyULRHDSUHQGHUiSRUTXH
HOHpXPDyWLPDRSomRSDUDPXLWRVDSOLFDWLYRV$R¿QDOGHVWHFDStWXORYRFr
será capaz de criar um aplicativo em camadas e bem projetado.
O capítulo 15 explica como integrar a Estrutura de Entidades em aplicativos ASP.NET. Neste capítulo, você lerá sobre os controles ASP.NET e sobre
as melhores práticas para manipulação de objetos. Isto permitirá que você crie
aplicativos web usando os padrões corretos.
O capítulo 16 discute como criar aplicativos de serviços web. Aqui, você
DSUHQGHUiVREUHIXQFLRQDOLGDGHVHVSHFt¿FDVGHGLFDGDVDRDPELHQWHGHVHUYLços web, e como e quando usá-las, em vez de recorrer a outras técnicas. Ao
¿QDOGHVWHFDStWXORYRFrWHUiXPIRUWHHQWHQGLPHQWRGDLQWHJUDomRGHVHUYLoRV
web com a Estrutura de Entidades.
O capítulo 17 explica como integrar a Estrutura de Entidades em aplicativos Windows. Aqui, você descobrirá como permitir que suas classes de
PRGHORLPSOHPHQWHPXPDLQWHUIDFHHVSHFt¿FDSDUDTXHHODVVHLQWHJUHPFRP
as capacidades de ligação de dados de aplicativos Windows Form e WPF. Ao
¿QDOGHVWHFDStWXORYRFrVHUiFDSD]GHHQIUHQWDURVSUREOHPDVFRWLGLDQRVTXH
envolvem esses tipos de aplicativos.
O capítulo 18 cobre o teste. Aqui, você aprenderá a testar o código que
acessa a base de dados e seus repositórios, e a criar baterias de testes para
UHYHODUVHVXDVPRGL¿FDo}HVLQWHUURPSHUDPDOJXPDFRLVD
O capítulo 19 discute o desempenho. Você aprenderá como o desempenho
da Estrutura de Entidades se compara ao desempenho na abordagem do ADO.
NET clássico. Você também aprenderá alguns truques e dicas para melhorar
RGHVHPSHQKRHPYiULDVVLWXDo}HV$R¿QDOGRFDStWXORYRFrVHUiFDSD]GH
levar ao extremo o desempenho de seu código de acesso a dados.
O apêndice A apresenta o LINQ. O LINQ para Entidades é a linguagem
de consulta mais popular para a Estrutura de Entidades. Ele é um dialeto do
LINQ, de modo que, para melhor entendê-lo, você deve ter um bom conhecimento do LINQ. É isso o que este apêndice oferece.
O apêndice B apresenta algumas boas dicas da Estrutura de Entidades.
Você não aprenderá novas funcionalidades, aqui, mas aprenderá a combinar
funcionalidades existentes para produzir comportamentos poderosos. Este é
Sobre este Livro - XV
seu último recurso no entendimento de quanto poder a Estrutura de Entidades
oferece a você.
Convenções de Código
Todo o código fonte em listagens ou à parte do texto está numa fonte
como esta, para separá-lo do texto comum. O código
.NET é fornecido tanto em C# quanto em Visual Basic, de modo que você
deve se sentir à vontade com ele, qualquer que seja sua linguagem de desenvolvimento. Para linhas mais longas de código, que não cabem na página,
um caractere de continuação de código ( ) é usado para indicar as linhas
que estão quebradas na página, mas que não devem ser quebradas no código.
Anotações de código acompanham muitas das listagens, destacando conceitos
importantes. Em alguns casos, marcas numeradas fazem a ligação para explicações que seguem a listagem.
Downloads do código fonte
Todos os exemplos deste livro podem ser baixados no site da Editora
Ciência Moderna (www.lcm.com.br). O código vem em versões para VB e
para C#. O código vem com um arquivo de solução Visual Studio 2010, de
modo que você só precisa do Visual Studio 2010 para rodar os exemplos. Nós
não tentamos abrir o arquivo de solução com o Visual Studio Express 2010
(que é a versão gratuita), mas ele provavelmente funciona.
Sobre os Autores
Stefano Mostarda é MVP da Microsoft, na categoria Plataforma de Dados,
é arquiteto de software focado em aplicativos web e co-fundador da 5DLabs.it,
uma agência de consultoria especializada em ASP.NET, Silverlight, Windows
3KRQH H QD (VWUXWXUD 1(7 6WHIDQR p SDOHVWUDQWH SUR¿VVLRQDO HP PXLWDV
conferências italianas sobre tecnologias da Microsoft, escreveu muitos livros
para o mercado italiano e é co-autor do ASP.NET 4.0 Na Prática, da Editora
Ciência Moderna. Ele é um dos líderes da Rede ASPItalia e gerente de conteúdo do website LINQNItalia, dedicado ao LINQ e à Estrutura de Entidades.
Marco De Sanctis tem projetado e desenvolvido aplicativos empresariais
em cenários distribuídos nos últimos sete anos. Começou a desenvolver com
o ASP.NET logo que este apareceu, e desde então, tornou-se arquiteto de
aplicativos. Ao longo dos anos, Marco se especializou na construção de serviços distribuídos, ampliando seu conhecimento para abranger tecnologias
FRPR :RUNÀRZ )RXQGDWLRQ :LQGRZV &RPPXQLFDWLRQ )RXQGDWLRQ /,14
e Estrutura de Entidades ADO.NET. Hoje, trabalha como engenheiro sênior
de software de grandes empresas italianas no mercado de TI. Em seu tempo
livre, é gerente de conteúdo da ASPItalia e foi recentemente nomeado MVP
da Microsoft no ASP.NET.
Daniele Bochicchio é co-fundador da 5DLabs, uma agência de consultoria especializada em ASP.NET, Silverlight, Windows Phone 7 e Estrutura
.NET. Trabalhou em muitos projetos interessantes com muitas tecnologias
GLIHUHQWHVeSDOHVWUDQWHSUR¿VVLRQDOHDXWRUEHPFRQKHFLGRWDQWRTXHSRGH
encontrá-lo em eventos com foco em desenvolvedores em todo o mundo. Ele
já escreveu vários livros em italiano e em inglês, incluindo o ASP.NET 4.0 in
Practice, publicado pela Manning e traduzido para o português pela Editora
Ciência Moderna. Daniele também é gerente de rede da ASPItalia, a maior
comunidade italiana da Estrutura .NET.
Sobre a Ilustração de Capa
$ ¿JXUD GD FDSD GR Entity Framework 4 – Estrutura de Entidades- em
Ação é intitulada “Limonaro”, ou vendedor de limões. A ilustração foi tirada
de uma coleção de 123"2
que inclui
desenhos coloridos à mão de trajes regionais italianos do século XIX. Vestindo uma camisa de linho branco, calções azuis e um chapéu de palha de abas
largas, e carregando uma cesta de limões numa mão e um jarro de limonada
QDRXWUDROLPRQDURHUDXPD¿JXUDLWLQHUDQWHEHPYLQGDQDVUXDVGHFLGDGHV
e vilas italianas, especialmente no tempo quente do verão.
A diversidade dos desenhos na coleção fala vivamente da unicidade e individualidade de cidades e províncias do mundo de apenas 200 anos atrás. Isoladas umas das outras, as pessoas falavam diferentes dialetos e línguas. Nas ruas
RXQRFDPSRHUDIiFLOLGHQWL¿FDURQGHHODVYLYLDPHTXDOHUDDVXDSUR¿VVmR
ou posição na vida só por aquilo que elas estavam vestindo.
Os códigos de vestuário mudaram, desde então, e a diversidade por região,
tão rica na época, desapareceu. Agora, é difícil distinguir o habitante de um
ou outro país. Talvez, procurando vê-lo de forma otimista, nós trocamos uma
diversidade cultural e visual por uma vida pessoal mais variada. Ou por uma
vida intelectual e técnica mais variada e interessante.
Sumário Resumido
........................... 1
...............................3
...............................................................47
!" ............................................85
#..................................................................................111
$%&' .......................................................113
(') .....................................................................173
* .........................................................221
! ..............................................................257
+,- ...............................................................297
/0 ...................................329
6:*;&$...........................331
XXII - Entity Framework 4 - A Estrutura de Entidades - em Ação
+<'= ...........................................369
+<:-* ...................................................................413
?'0(.....................................................................431
=@.................................................................469
GJJ'........................................515
JJ' ................................................................515
!'* ....................517
JJ;K%+ .........................................................547
J** .................571
J'*PQ.........................................609
+.................................................................643
0<'<.....................................................................................681
J',J..........................................................................................................717
J',V .........................................................................................................743
W ...........................................................................................................773
Sumário
Parte 1 - Redefinindo sua estratégia de acesso a dados ..............................1
O acesso a dados recarregado: a Estrutura de Entidades...............................3
1.1 Introdução ao acesso a dados .....................................................................4
1.2 Desenvolvendo aplicativos com estruturas no estilo de bases de dados .6
1.2.1 Usando datasets e leitores de dados como contentores de dados...6
1.2.2 O problema do acoplamento forte .................................................10
1.2.3 O problema tipificação fraca ..........................................................11
1.2.4 O problema do desempenho...........................................................13
1.3 Usando classes para organizar dados .......................................................14
1.3.1 Usando classes para representar dados ..........................................15
1.3.2 De uma única classe ao modelo de objeto.....................................18
1.4 Aprofundando as diferenças entre objeto e relacional ............................21
1.4.1 A incompatibilidade de tipos de dados ..........................................21
1.4.2 A incompatibilidade de associação ................................................22
RELACIONAMENTOS UM-PARA-UM.......................................................22
RELACIONAMENTOS UM-PARA-MUITOS ................................................23
RELACIONAMENTOS MUITOS-PARA-MUITOS .........................................24
1.4.3 A incompatibilidade de granularidade ...........................................25
1.4.4 A incompatibilidade de herança .....................................................28
1.4.5 A incompatibilidade de identidade .................................................29
XXIV - Entity Framework 4 - A Estrutura de Entidades - em Ação
1.4.6 Tratando as incompatibilidades ......................................................31
1.5 Deixando que a Estrutura de Entidades facilite sua vida........................32
1.5.1 O que é O/RM? ...............................................................................33
1.5.2 Os benefícios do uso da Estrutura de Entidades ...........................34
1.5.3 Quando é que o O/RM não é necessário? .....................................37
1.6 Como Estrutura de Entidades realiza o acesso a dados ..........................38
1.6.1 O Modelo de Dados da Entidade ...................................................39
O MODELO CONCEITUAL .....................................................................40
O MODELO DE ARMAZENAMENTO ........................................................41
O MODELO DE MAPEAMENTO ..............................................................41
O ARQUIVO DE MAPEAMENTO DO VISUAL STUDIO ................................41
1.6.2 Serviços de Objetos.........................................................................42
1.6.3 O provedor de dados do Cliente da Entidade ................................44
1.6.4 O LINQ para Entidades ..................................................................44
1.6.5 O SQL da Entidade .........................................................................45
1.7 Resumo ......................................................................................................46
Introdução à Estrutura de Entidades ...............................................................47
2.1 Apresentando o exemplo OrderIT............................................................48
2.2 Projetando o modelo de OrderIT e a base de dados ...............................50
2.2.1 Comparando os projetos de baixo para cima e de cima
para baixo ..................................................................................................51
2.2.2 Clientes e fornecedores ...................................................................52
2.2.3 Produtos ...........................................................................................55
2.2.4 Pedidos.............................................................................................57
2.3 Estruturando do aplicativo........................................................................60
2.3.1 Criando as montagens.....................................................................60
2.3.2 Projetando entidades com a abordagem de primeiro a base de
dados..........................................................................................................61
Sumário - XXV
IMPORTANDO A BASE DE DADOS ..........................................................63
CRIANDO ENTIDADES A PARTIR DO ZERO ..............................................64
MODIFICANDO ENTIDADES SIMILARES A TABELAS DA BASE DE DADOS ..69
2.3.3 Projetando relacionamentos ...........................................................70
2.3.4 Organizando o código gerado ........................................................73
2.3.5 A abordagem de primeiro o modelo, no designer .........................76
2.4 Uma olhadela no código ...........................................................................77
2.4.1 Consultando a base de dados..........................................................77
2.4.2 Atualizando objetos e refletindo mudanças no armazenamento ..79
INSERÇÕES .........................................................................................79
ATUALIZAÇÕES ...................................................................................81
EXCLUSÕES ........................................................................................82
2.5 Resumo ......................................................................................................84
Consultando o modelo de objeto: Fundamentos ............................................85
3.1 Um mecanismo, muitos métodos de consulta.........................................85
3.2 O ponto de entrada do mecanismo de consultas: os Serviços de
Objetos .............................................................................................................86
3.2.1 Configurando a string de conexão .................................................90
CRIANDO STRINGS DE CONEXÃO NO CÓDIGO........................................91
3.2.2 Escrevendo consultas contra as classes .........................................95
3.2.3 Consultas LINQ para Entidades e consultas LINQ padrões ........96
3.2.4 Recuperando dados da base de dados............................................97
3.2.5 Entendendo o Mapa de Identidade no contexto ............................98
CREATEOBJECTSET<T> E RASTREAMENTO..........................................100
EXECUTE E RASTREAMENTO..............................................................101
3.2.6 Entendendo a interação entre Serviços de Objetos e Cliente de
Entidade .........................................................................................................102
3.2.7 Capturando o SQL gerado ............................................................103
XXVI - Entity Framework 4 - A Estrutura de Entidades - em Ação
3.2.8 Entendendo que entidades são retornadas por uma consulta .....104
3.2.9 Quando uma consulta é executada? .............................................106
3.2.10 Gerenciando a base de dados a partir do contexto ....................108
3.3 Resumo ....................................................................................................109
Parte 2 - Começando .........................................................................................111
Consultando com LINQ para Entidades .......................................................113
Qual é o futuro do LINQ para SQL? .................................................113
4.1 Filtrando dados ........................................................................................ 114
4.1.1 Filtrando dados com base em associações .................................. 116
FILTRANDO COM UMA ÚNICA ASSOCIAÇÃO ........................................ 116
FILTRANDO COM ASSOCIAÇÕES DE COLEÇÕES.................................... 118
4.1.2 Paginando resultados ....................................................................121
4.1.3 Recuperando uma entidade ..........................................................123
USANDO MÉTODOS DO CONTEXTO .....................................................124
4.1.4 Criando consultas dinamicamente ...............................................126
4.2 Projetando resultados ..............................................................................127
4.2.1 Projetando com associações .........................................................130
PROJETANDO COM UMA ÚNICA ASSOCIAÇÃO ......................................131
PROJETANDO COM ASSOCIAÇÕES COLEÇÕES ......................................134
4.2.2 Projeções e rastreamento de objetos ............................................136
4.3 Agrupando dados ....................................................................................137
4.3.1 Filtrando dados agregados ............................................................142
4.4 Ordenando ...............................................................................................144
4.4.1 Ordenando com associações ........................................................145
4.5 Juntando dados ........................................................................................147
4.6 Consultando com herança ......................................................................151
Sumário - XXVII
4.7 Usando funções .......................................................................................155
4.7.1 Funções canônicas ........................................................................155
4.7.2 Funções de bases de dados ...........................................................157
4.8 Executando consultas feitas à mão ........................................................158
4.8.1 Trabalhando com parâmetros ....................................................... 161
USANDO LISTAS NUMERADAS ............................................................ 161
USANDO PARÂMETROS CLÁSSICOS ....................................................162
4.9 Buscando .................................................................................................164
4.9.1 O carregamento ávido...................................................................165
4.9.2 O carregamento lasso....................................................................167
4.9.3 Carregamento manual adiado.......................................................168
4.9.4 Escolhendo uma estratégia de carregamento ..............................171
4.10 Resumo ..................................................................................................171
Mapeando o modelo de domínio .....................................................................173
5.1 O Modelo de Dados de Entidades ......................................................... 174
5.1.1 O Modelo de Dados de Entidades e o designer do Visual
Studio ...................................................................................................... 175
5.2 Criar entidades consumíveis...................................................................178
5.2.1 Escrevendo as entidades ...............................................................179
5.2.2 Descrevendo entidades no esquema conceitual ..........................183
SCHEMA ...........................................................................................184
EntityContainer .....................................................................................184
COMPLEXTYPE E ENTITYTYPE ...........................................................186
5.2.3 Descrevendo a base de dados no esquema de armazenamento .189
SCHEMA ...........................................................................................190
ENTITYCONTAINER ...........................................................................190
ENTITYTYPE .....................................................................................191
5.2.4 Criando o arquivo de mapeamento ..............................................193
XXVIII - Entity Framework 4 - A Estrutura de Entidades - em Ação
MAPPING E ENTITYCONTAINERMAPPING ............................................194
ENTITYSETMAPPING, ENTITYTYPEMAPPING E MAPPINGFRAGMENT.....195
SCALARPROPERTY E COMPLEXPROPERTY ..........................................196
5.3 Definindo relacionamentos no modelo..................................................198
5.3.1 Relacionamentos um-para-um .....................................................198
MODIFICANDO A CLASSE ...................................................................198
MODIFICANDO O ESQUEMA CONCEITUAL ...........................................199
MODIFICANDO O ESQUEMA DE ARMAZENAMENTO .............................202
MODIFICANDO O ESQUEMA DE MAPEAMENTO ....................................204
5.3.2 Relacionamentos um-para-muitos ...............................................204
ADICIONANDO UMA PROPRIEDADE À CLASSE MÃE .............................204
MODIFICANDO O ESQUEMA CONCEITUAL ...........................................206
5.3.3 Relacionamentos muitos-para-muitos .........................................207
MODIFICANDO O ESQUEMA DE MAPEAMENTO ....................................207
5.3.4 Algumas dicas sobre relacionamentos .........................................208
5.4 Mapeando herança ..................................................................................209
5.4.1 Herança tabela por hierarquia.......................................................209
PROJETANDO AS CLASSES ..................................................................209
MODIFICANDO O ESQUEMA CONCEITUAL ...........................................210
MODIFICANDO O ESQUEMA DE MAPEAMENTO ....................................212
5.4.2 Herança tabela por tipo ................................................................. 214
5.5 Estendendo o EDM com anotações personalizadas ............................. 216
5.5.1 Personalizando o EDM................................................................. 217
5.6 Resumo .................................................................................................... 218
Entendendo o ciclo de vida da entidade .........................................................221
6.1 O ciclo de vida de entidade.....................................................................222
6.1.1 Entendendo o estado da entidade .................................................222
6.1.2 Como o estado da entidade afeta a base de dados ......................224
Sumário - XXIX
6.1.3 Mudanças de estado no ciclo de vida da entidade ......................224
ESTADO DETACHED ...........................................................................224
ESTADO UNCHANGED ........................................................................225
ESTADO ADDED .................................................................................225
ESTADO CHANGED ............................................................................225
ESTADO DELETED .............................................................................226
6.2 Gerenciando o estado da entidade..........................................................226
6.2.1 O método AddObject ....................................................................227
6.2.2 O método Attach ...........................................................................230
6.2.3 Os métodos ApplyCurrentValues e ApplyOriginalValues .........231
6.2.4 O método DeleteObject ................................................................233
6.2.5 O método AcceptAllChanges.......................................................234
6.2.6 Os métodos ChangeState e ChangeObjectState..........................235
6.2.7 O método Detach ..........................................................................236
6.3 Gerenciando o rastreamento de mudanças com o
ObjectStateManager......................................................................................237
6.3.1 A classe ObjectStateEntry.............................................................238
ENTENDENDO COMO O GERENCIADOR DE ESTADOS IDENTIFICA UM OBJETO
POR SUA CHAVE ................................................................................239
6.3.2 Recuperando entradas ...................................................................240
RECUPERANDO UMA ÚNICA ENTRADA ...............................................242
6.3.3 Modificando o estado da entidade a partir da entrada ............... 244
6.3.4 Entendendo o rastreamento de objetos ........................................245
RASTREAMENTO DE MUDANÇAS DE UMA ENTIDADE NÃO EMPACOTADA
NUM PROXY......................................................................................246
O RASTREAMENTO DE MUDANÇAS EMPACOTADO NUM PROXY ...........247
6.3.5 Entendendo o rastreamento de relacionamentos.........................249
ALTERAÇÕES SÓ SÃO RASTREADAS QUANDO AS ENTIDADES SÃO
XXX - Entity Framework 4 - A Estrutura de Entidades - em Ação
RASTREADAS PELO CONTEXTO ..........................................................251
O GERENCIADOR DE ESTADOS NÃO SUPORTA GRAFOS PARCIALMENTE CARREGADOS .........................................................................................251
COMO OS RELACIONAMENTOS MUDAM EM PROPRIEDADES DE REFERÊNCIA ÚNICA ........................................................................................251
COMO OS RELACIONAMENTOS MUDAM EM PROPRIEDADES DE
COLEÇÃO..........................................................................................252
6.3.6 O rastreamento de alterações e MergeOption .............................254
6.4 Resumo .............................................................................................256
Persistindo objetos na base de dados ..............................................................257
7.1 Persistindo entidades com SaveChanges...............................................258
7.1.1 Detectando entidades sujas...........................................................259
7.1.2 Iniciando transações na base de dados.........................................260
7.1.3 Geração e execução de código SQL ............................................260
7.1.4 Confirmação ou reversão da transação da base de dados ...........261
7.1.5 Confirmando entidades .................................................................261
7.1.6 Sobrepondo SaveChanges ............................................................262
7.2 Persistindo entidades modificadas na base de dados .....................263
7.2.1 Persistindo uma entidade como uma nova linha.........................263
7.2.2 Persistindo modificações feitas a uma entidade existente ..........266
PERSISTÊNCIA NO CENÁRIO CONECTADO ...........................................266
PERSISTÊNCIA NO CENÁRIO DESCONECTADO......................................267
ESCOLHENDO AS PROPRIEDADES A SEREM ATUALIZADAS NO CENÁRIO
DESCONECTADO ...............................................................................272
7.2.3 Persistindo exclusões de entidades ..............................................273
7.3 Persistindo grafos de entidades ..............................................................274
7.3.1 Persistindo um grafo de entidades adicionadas...........................274
PERSISTINDO UM GRAFO DE ENTIDADES ADICIONADAS USANDO
Sumário - XXXI
ASSOCIAÇÕES DE CHAVE EXTERNA ....................................................275
PERSISTINDO UM GRAFO DE ENTIDADES ADICIONADAS USANDO ASSOCIAÇÕES INDEPENDENTES ......................................................................277
PERSISTINDO UM GRAFO DE ENTIDADES EM DIFERENTES ESTADOS .....280
7.3.2 Persistindo modificações feitas num grafo ..................................281
PERSISTINDO MODIFICAÇÕES USANDO ASSOCIAÇÕES DE CHAVE
EXTERNA..........................................................................................281
PERSISTINDO MODIFICAÇÕES USANDO ASSOCIAÇÕES
INDEPENDENTES ...............................................................................285
7.3.3 Persistindo exclusões feitas a um grafo .......................................286
PERSISTINDO EXCLUSÕES COM ASSOCIAÇÕES DE CHAVE EXTERNA .....286
PERSISTINDO EXCLUSÕES USANDO ASSOCIAÇÕES INDEPENDENTES ....288
7.3.4 Persistindo relacionamentos muitos-para-muitos .......................290
7.4 Alguns truques relacionados com persistência......................................291
7.4.1 Tratando exceções de persistência ...............................................291
7.4.2 Executando comandos SQL personalizados ...............................292
7.5 Resumo ....................................................................................................294
Tratando concorrência e transações ...............................................................297
8.1 Entendendo o problema da concorrência ..............................................298
8.1.1 O cenário de atualizações concorrentes .......................................298
8.1.2 A primeira solução: controle pessimista de concorrência...........300
8.1.3 Uma solução melhor: controle otimista de concorrência ...........301
8.1.4 A solução intermediária: controle de concorrência pessimista/otimista ........................................................................................................303
8.2 Tratando a concorrência na Estrutura de Entidades ..............................304
8.2.1 Habilitando a verificação otimista de concorrência ....................304
8.2.2 A concorrência otimista em ação .................................................306
TRATANDO A CONCORRÊNCIA NO CENÁRIO CONECTADO.....................306
XXXII - Entity Framework 4 - A Estrutura de Entidades - em Ação
TRATANDO A CONCORRÊNCIA NO CENÁRIO DESCONECTADO COM
CHANGEOBJECTSTATE .......................................................................306
TRATANDO A CONCORRÊNCIA NO CENÁRIO DESCONECTADO COM
APPLYCURRENTVALUES ....................................................................307
TRATANDO A CONCORRÊNCIA COM GRAFOS NOS CENÁRIOS CONECTADO E
DESCONECTADO ............................................................................... 310
CONCORRÊNCIA OTIMISTA E HERANÇA .............................................. 310
8.2.3 Capturando exceções de concorrência.........................................312
8.2.4 Gerenciando exceções de concorrência .......................................313
ATUALIZANDO VALORES A PARTIR DA DATABASE ................................ 314
CONSTRUINDO O FORMULÁRIO DE COMPARAÇÃO .............................. 316
8.3 Gerenciando transações ..........................................................................322
8.3.1 O ObjectContext transacional ......................................................325
8.3.2 Transações e consultas ..................................................................326
8.4 Resumo ....................................................................................................327
Parte 3 - Dominando a Estrutura de Entidades .......................................329
Uma forma alternativa de consulta: o SQL de Entidades...........................331
9.1 Fundamentos de consultas......................................................................333
9.2 Filtrando dados ........................................................................................335
9.2.1 Trabalhando com associações ......................................................336
FILTRAGEM COM UMA ÚNICA ASSOCIAÇÃO ........................................336
FILTRAGEM COM ASSOCIAÇÕES DE COLEÇÕES ...................................336
9.2.2 Paginando resultados ....................................................................338
9.3 Projetando resultados .......................................................................339
9.3.1 Tratando os resultados da projeção ..............................................339
9.3.2 Projetando com associações .........................................................343
Sumário - XXXIII
PROJETANDO COM ASSOCIAÇÕES ÚNICAS...........................................343
PROJETANDO COM ASSOCIAÇÕES DE COLEÇÃO...................................344
9.4 Agrupando dados ....................................................................................346
9.5 Ordenando dados ....................................................................................348
9.5.1 Ordenando dados baseados em associações................................349
9.6 Juntando dados ........................................................................................350
9.7 Consultando a herança ............................................................................350
9.8 Usando métodos construtores de consultas ...........................................351
9.8.1 Encadeando métodos ....................................................................353
9.8.2 Os métodos construtores de consultas e os métodos do LINQ para
Entidades .................................................................................................356
9.8.3 Usando parâmetros para evitar injeção........................................357
TRADUÇÃO DE PARÂMETROS.............................................................358
9.9 Trabalhando com o provedor de dados do Cliente de Entidades .........359
9.9.1 Conectando com EntityConnection .............................................361
9.9.2 Executando consultas com EntityCommand ..............................362
9.9.3 Processando resultados de consultas com EntityDataReader ....363
TRANSFORMANDO UM DBDATAREADER EM OBJETOS .........................364
9.9.4 Indo além das consultas com o Cliente de Entidades .................366
9.10 Resumo ..................................................................................................367
Trabalhando com procedimentos armazenados ...........................................369
10.1 Mapeando procedimentos armazenados .............................................370
10.1.1 Importando um procedimento armazenado com o designer....371
10.1.2 Importando procedimentos armazenados manualmente ..........373
DEFININDO UM PROCEDIMENTO ARMAZENADO NO ESQUEMA DE ARMAZENAMENTO ...........................................................................
373
DEFININDO UMA FUNÇÃO NO ESQUEMA CONCEITUAL ...................374
XXXIV - Entity Framework 4 - A Estrutura de Entidades - em Ação
LIGANDO UM PROCEDIMENTO ARMAZENADO A UMA FUNÇÃO NO
ESQUEMA DE MAPEAMENTO ......................................................375
10.2 Retornando dados com procedimentos armazenados ........................376
10.2.1 Procedimentos armazenados cujos resultados
correspondem a uma entidade ...............................................................377
COMO OS RESULTADOS DE UM PROCEDIMENTO ARMAZENADO SÃO MAPEADOS PARA UMA CLASSE ...................................................................379
10.2.2 Procedimentos armazenados cujos resultados não correspondem
a uma entidade ........................................................................................380
PROCEDIMENTOS ARMAZENADOS CUJOS RESULTADOS TÊM COLUNAS QUE
NÃO SE ALINHAM COM UMA ENTIDADE ..............................................381
PROCEDIMENTOS ARMAZENADOS CUJOS NOMES DE COLUNAS DO RESULTADO SÃO DIFERENTES DAS PROPRIEDADES DA ENTIDADE .................385
PROCEDIMENTOS ARMAZENADOS QUE RETORNAM RESULTSETS DE UMA
ENTIDADE COM TIPOS COMPLEXOS ....................................................387
10.2.3 Procedimentos armazenados que retornam valores escalares..387
10.2.4 Procedimentos armazenados que retornam uma hierarquia de
herança ....................................................................................................389
RETORNANDO UMA HIERARQUIA MAPEADA COM A ESTRATÉGIA TPH ...390
RETORNANDO UMA HIERARQUIA MAPEADA COM A ESTRATÉGIA TPT ...391
10.2.5 Procedimentos armazenados com parâmetros de saída ...........394
PARÂMETROS DE SAÍDA NUM SEGUNDO RESULTSET ...........................398
10.3 Embutindo funções no modelo de armazenamento............................399
10.4 Atualizando dados com procedimentos armazenados ........................401
10.4.1 Usando procedimentos armazenados para persistir uma
entidade ...................................................................................................402
PROCEDIMENTOS ARMAZENADOS QUE PERSISTEM UMA ENTIDADE E O
EDM .................................................................................................405
Sumário - XXXV
10.4.2 Usando procedimentos armazenados para atualizar uma entidade
com concorrência .................................................................................. 406
10.4.3 Persistindo uma entidade que está numa hierarquia de
herança ....................................................................................................408
USANDO UM PROCEDIMENTO ARMAZENADO PARA PERSISTIR UM HIERARQUIA ................................................................................................408
10.4.4 Elevando e rebaixando uma entidade que está numa hierarquia de
herança ....................................................................................................410
10.4.5 Executando procedimentos armazenados não ligados a uma entidade ......................................................................................................... 411
10.5 Resumo ..................................................................................................412
Trabalhando com funções e vistas ...................................................................413
11.1 Vistas no modelo de armazenamento: consultas definidoras ............. 414
11.1.1 Criando uma consulta definidora ............................................... 414
11.2 Funções definidas pelo usuário e funções com valor escalar ............. 418
11.2.1 Funções com valores escalares...................................................419
11.2.2 Funções definidas pelo usuário ..................................................422
PASSANDO UM OBJETO COMO PARÂMETRO DE UMA FUNÇÃO ..............424
RETORNANDO UM OBJETO NÃO TIPIFICADO DE UMA FUNÇÃO .............424
RETORNANDO UM OBJETO TIPIFICADO DE UMA FUNÇÃO .....................426
11.2.3 Funções definidas pelo usuário e os resultados de coleções ....427
RETORNANDO UMA LISTA DE VALORES ESCALARES ............................427
RETORNANDO UMA LISTA DE OBJETOS GENÉRICOS .............................427
RETORNANDO UMA LISTA DE OBJETOS TIPIFICADOS............................428
11.3 Resumo ..................................................................................................429
Explorando metadados do EDM.....................................................................431
12.1 Fundamentos de metadados .................................................................432
XXXVI - Entity Framework 4 - A Estrutura de Entidades - em Ação
12.1.1 Acessando metadados .................................................................433
ACESSANDO METADADOS COM O CONTEXTO .....................................433
ACESSANDO METADADOS COM A CONEXÃO .......................................434
ACESSANDO METADADOS COM A CLASSE METADATAWORKSPACE .......434
12.1.2 Como os metadados são organizados internamente .................436
12.1.3 Entendendo quando os metadados se tornam disponíveis .......437
12.2 Recuperando metadados ................................................................439
12.2.1 Entendendo o modelo de objeto de metadados.........................439
12.2.2 Extraindo metadados do EDM...................................................441
EXTRAINDO METADADOS COM GETITEMS ..........................................441
EXTRAINDO METADADOS COM GETITEMCOLLECTION ........................442
E TRYGETITEMCOLLECTION ..............................................................442
EXTRAINDO METADADOS COM GETITEMS<T> .....................................443
EXTRAINDO METADADOS COM GETITEM<T> E TRYGETITEM<T> ......... 444
12.3 Construindo um explorador de metadados..........................................445
12.3.1 Preenchendo entidades e tipos complexos ................................447
RECUPERANDO TIPOS BASES DA ENTIDADE ....................................... 448
RECUPERANDO ENTIDADES DERIVADAS DE ENTIDADES ......................449
RECUPERANDO PROPRIEDADES .........................................................450
RECUPERANDO TIPOS COMPLEXOS ....................................................454
12.3.2 Preenchendo funções ..................................................................455
12.3.3 Preenchendo os contentores .......................................................457
12.3.4 Preenchendo nós de armazenamento.........................................460
12.4 Escrevendo código genérico com metadados ..............................462
12.4.1 Adicionando ou anexando um objeto com base em anotações personalizadas ..............................................................................................462
12.4.2 Construindo um método GetById genérico ..............................466
12.5 Resumo ..................................................................................................468
Sumário - XXXVII
Personalizando código e o designer.................................................................469
13.1 Como o Visual Studio gera classes ......................................................470
13.1.1 Entendendo as marcas de gabaritos ...........................................472
13.1.2 Entendendo as diretivas ..............................................................473
13.1.3 Escrevendo código ......................................................................474
13.2 Personalizando a geração de classes ....................................................477
13.2.1 Entendendo o gabarito POCO disponível .................................477
13.2.2 Gerando funções definidas pelo usuário e com valor escalar ..478
13.2.3 Gerando atributos de anotação de dados ...................................485
13.2.4 Estendendo classes através de classes parciais .........................487
13.3 Como o Visual Studio gera a DDL da base de dados ..................489
13.3.1 Escolhendo o fluxo de trabalho ..................................................490
13.3.2 Gerando o SSDL, o MSL e a DDL............................................492
13.4 Personalizando a geração da DDL.......................................................494
13.4.1 Entendendo o gabarito conceitual-para-armazenamento .........494
13.4.2 Entendendo o gabarito conceitual-para-mapeamento ..............497
13.4.3 Entendendo o gabarito do script ................................................499
armazenamento-para-base-de-dados.....................................................499
13.5 Criando extensões do designer.............................................................500
13.5.1 Como funciona o mecanismo de extensão de propriedades ....501
13.5.2 Configurando o projeto que contém a extensão........................502
13.5.3 Criando a classe de propriedade.................................................503
13.5.4 Criando a classe produtora .........................................................507
13.5.5 Criando o arquivo de extensão de manifesto ............................510
13.5.6 Instalação, depuração e desinstalação de extensões ................. 511
13.6 Resumo ..................................................................................................513
Parte 4 - A Estrutura de Entidades Aplicada.............................................515
XXXVIII - Entity Framework 4 - A Estrutura de Entidades - em Ação
A Estrutura de Entidades Aplicada ................................................................515
Projetando o aplicativo em torno da Estrutura de Entidades ....................517
14.1 O processo de design do aplicativo...................................................... 518
14.2 Uma típico arquitetura em três camadas .............................................520
14.2.1 Preenchendo a lista de produtos .................................................520
14.2.2 Calculando totais de pedidos e salvando-os na base de dados.523
14.2.3 Lidando com níveis mais altos de complexidade .....................525
14.3 Princípios de design dirigido pelo domínio.........................................526
14.3.1 Entidades .....................................................................................527
14.3.2 Objetos de valor ..........................................................................529
14.3.3 Tratando associações corretamente: ..........................................530
raízes de domínio e agregados...............................................................530
14.3.4 Refinando o modelo....................................................................533
14.4 Recuperando referências a uma entidade do domínio ........................537
14.4.1 Repositórios de relance...............................................................537
14.4.2 Implementando um repositório ..................................................538
14.4.3 Obtendo uma referência a uma nova entidade ......................... 544
14.5 Resumo ..................................................................................................545
A Estrutura de Entidades e o ASP.NET .........................................................547
15.1 EntityDataSource: uma nova abordagem para a ligação de dados ....548
15.1.1 Guia prático para os controles de fontes de dados ....................548
O CONTROLE SQLDATASOURCE ..........................................................549
O CONTROLE OBJECTDATASOURCE ....................................................549
OS CONTROLES LINQDATASOURCE E ENTITYDATASOURCE ..................549
15.1.2 O controle EntityDataSource a fundo........................................550
15.2 Usando controles de Dados Dinâmicos com a Estrutura de Entidades............................................................................................................555
Sumário - XXXIX
15.2.1 Registrando o modelo .................................................................555
15.2.2 Trabalhando com anotações de dados .......................................558
15.3 O ciclo de vida de ObjectContext no ASP.NET..................................561
15.3.1 O padrão Contexto-por-Requisição ...........................................562
15.3.2 Empacotando o contexto ............................................................563
15.3.3 Um módulo para tratar o ciclo de vida ......................................565
15.3.4 Usando o repositório numa página ............................................567
15.4 Cenários comuns envolvendo o ASP.NET e a Estrutura de
Entidades........................................................................................................568
15.5 Resumo ..................................................................................................569
A Estrutura de Entidades e o desenvolvimento em n-camadas .................571
16.1 Problemas e soluções com n-camadas.................................................572
16.1.1 Rastreando alterações feitas no cliente ......................................572
16.1.2 Escolhendo dados a serem trocados entre servidor e cliente ...574
16.1.3 O problema da serialização ........................................................575
16.2 Desenvolvendo um serviço usando entidades como contratos..........577
16.2.1 Persistindo um grafo complexo .................................................581
16.2.2 Otimizando as trocas de dados entre cliente e servidor ............582
16.2.3 Lidando com serialização na WCF............................................584
CUIDADO COM O CARREGAMENTO LASSO QUANDO SERIALIZANDO ....588
16.3 Desenvolvendo um serviço usando DTOs ..........................................589
16.3.1 Persistindo um grafo complexo .................................................593
16.4 Desenvolvendo um serviço usando STEs ...........................................595
16.4.1 Habilitando STEs ........................................................................596
16.4.2 Dentro de uma STE ....................................................................597
ENTENDENDO O RASTREADOR DE ALTERAÇÕES DA ENTIDADE ............598
COMO O RASTREADOR DE ALTERAÇÕES DETECTA MODIFICAÇÃO DA ENTIDADE................................................................................................599
XL - Entity Framework 4 - A Estrutura de Entidades - em Ação
GERENCIANDO O ESTADO DA ENTIDADE............................................ 600
16.4.3 Dentro do contexto..................................................................... 600
16.4.4 Usando STEs ...............................................................................601
ATUALIZANDO UM GRAFO COMPLEXO COM STES ...............................603
ADICIONANDO OU EXCLUINDO UMA ENTIDADE USANDO STES ........... 604
RELACIONAMENTOS MUITOS-PARA-MUITOS E AS STES ....................... 604
ESTADO INTERNO E ESTADO DO CONTEXTO ........................................606
16.4.5 Prós e contras das STEs..............................................................606
16.5 Resumo ..................................................................................................607
A Estrutura de Entidades e aplicativos Windows........................................ 609
17.1 Um aplicativo de exemplo....................................................................610
17.2 Projetando classes de modelo para ligação ......................................... 611
17.2.1 Implementando INotifyPropertyChanged................................. 611
17.2.2 Implementando IEditableObject ................................................ 614
17.2.3 Implementando IDataErrorInfo ................................................. 617
17.2.4 Usando um gabarito para gerar o código de ligação.................620
17.3 Ligando aplicativos Windows Forms ..................................................622
17.3.1 Mostrando pedidos......................................................................622
17.3.2 Exibindo dados do pedido selecionado .....................................625
ADICIONANDO UMA CAIXA COMBO DE BUSCA PARA EXIBIR E ALTERAR UM
CLIENTE ...........................................................................................625
17.3.3 Exibindo detalhes do pedido selecionado .................................626
17.3.4 Exibindo informações do detalhe selecionado..........................628
17.3.5 Adicionando código para persistir modificações ......................629
MODIFICANDO UM PEDIDO ................................................................629
EXCLUINDO UM PEDIDO ....................................................................630
EXCLUINDO UM DETALHE .................................................................630
CRIANDO UM PEDIDO ........................................................................631
Sumário - XLI
17.3.6 Tirando proveito das interfaces de ligação ................................633
17.4 Ligando aplicativos WPF .....................................................................634
17.4.1 Exibindo pedidos ........................................................................634
17.4.2 Exibindo dados do pedido selecionado .....................................636
17.4.3 Exibindo detalhes do pedido selecionado .................................637
17.4.4 Exibindo informações do detalhe selecionado..........................638
17.4.5 Adicionando código para persistir modificações ......................639
EXCLUINDO E ADICIONANDO UM PEDIDO ...........................................639
EXCLUINDO UM DETALHE .................................................................641
17.5 Resumo ..................................................................................................641
Testando a Estrutura de Entidades.................................................................643
18.1 Testes de unidade num relance............................................................ 644
18.2 Escrevendo um conjunto de testes no Visual Studio 2010.................648
18.2.1 Testando um método simples .....................................................648
18.2.2 Funcionalidades avançadas da Estrutura de Testes de Unidade da
Microsoft .................................................................................................651
18.3 Isolando dependências ...................................................................654
18.3.1 Refazendo para a testabilidade ...................................................655
18.3.2 Usando uma estrutura de simulação para falsear
dependências...........................................................................................659
18.4 Teste de unidade da camada de acesso a dados...................................663
18.4.1 Uma infraestrutura de testes para um repositório .................... 664
18.4.2 Testando consultas LINQ para Entidades .................................669
18.5 Testando a persistência e recuperação de uma entidade .....................675
18.6 Resumo ..................................................................................................679
De olho no desempenho.....................................................................................681
19.1 Configuração e ambiente de teste ........................................................682
XLII - Entity Framework 4 - A Estrutura de Entidades - em Ação
19.1.1 O visualizador do teste de desempenho.....................................684
19.1.2 Construindo o temporizador.......................................................685
19.2 Comparação de escrita na base de dados.............................................690
19.3 Comparações de consultas no ambiente omissivo..............................694
19.4 Otimizando o desempenho ...................................................................700
19.4.1 Gerando vistas previamente .......................................................700
GERANDO VISTAS PREVIAMENTE ATRAVÉS DE GABARITO ...................703
19.4.2 Compilando consultas LINQ para Entidades............................706
ESCREVENDO UMA CONSULTA COMPILADA ........................................707
DETALHES INTERNOS DE CONSULTAS COMPILADAS ............................709
19.4.3 Habilitando o uso de cache plano para o SQL de Entidades.... 711
19.4.4 Desabilitando o rastreamento quando ele não é necessário .....712
19.4.5 Otimizando procedimentos armazenados .................................714
19.5 Resumo ..................................................................................................716
Apêndice A ..........................................................................................................717
A.1 Por que o LINQ foi criado? ...................................................................717
A.2 Inferência de tipo....................................................................................721
A.3 Métodos de extensão..............................................................................722
A.3.1 Encadeamento de métodos ..........................................................727
A.3.2 Avaliação de métodos ..................................................................728
A.4 Expressões lambda.................................................................................731
A.4.1 Métodos anônimos .......................................................................731
A.4.2 Dos métodos anônimos às expressões lambda ..........................733
A.5 inicializadores de objetos.......................................................................735
A.6 Tipos anônimos ......................................................................................737
A.7 Sintaxe de consulta.................................................................................738
A.8 Execução deferida ..................................................................................739
A.8.1 Composição de consulta em tempo de execução.......................740
Sumário - XLIII
B.1 Uma maneira inteligente de anexar entidades ......................................743
Apêndice B .........................................................................................................743
B.1.1 Anexando uma entidade como Modified ou Deleted ................744
B.1.2 Modificando apenas propriedades selecionadas após a
anexação..................................................................................................746
B.2 Construindo um sistema de auditagem .................................................750
B.2.1 Criando um atributo para marcar entidades auditáveis ..............751
B.2.2 Personalizando o designer ...........................................................751
B.2.3 Personalizando o gabarito que gera entidades ............................755
B.2.4 Sobrepondo o processo de persistência com um contexto personalizado .......................................................................................................756
B.2.5 Personalizando o gabarito do contexto .......................................762
B.2.6 Usando o código ...........................................................................763
B.3 Duas dicas para consulta de dados ........................................................765
B.3.1 Melhorando o método Include ....................................................765
B.3.2 Habilitando a pesquisa de texto completo na Estrutura de
Entidades .................................................................................................767
B.4 Trabalhando com tipos de bases de dados especiais ............................767
Índice ......................................................................................................................773
7895
Parte 1
5
acesso a dados
Bem-vindo ao Entity Framework 4 – A Estrutura de Entidades – em Ação.
A Estrutura de Entidades é a ferramenta de O/RM que a Microsoft introduziu
com a .NET Framework 3.5 Service Pack 1 e que agora atualizou para a versão 4.0. Este livro permitirá que você use a Estrutura de Entidades 4.0 para
construir rapidamente aplicativos centrados em dados de uma forma robusta e
dirigida pelo modelo. Se for novato com a Estrutura de Entidades, você aprenderá a criar um aplicativo a partir do zero e construí-lo corretamente. Se for
um desenvolvedor experiente com a Estrutura de Entidades, você encontrará
montes de abordagens profundas que melhorarão seu conhecimento desta poderosa ferramenta.
O livro está dividido em quatro partes, e parte 1 mergulha diretamente nos
fundamentos da Estrutura de Entidades. No capítulo 1, você descobrirá o que
é uma ferramenta de O/RM, e quando e por que ela deve ser usada. Depois,
você aprenderá sobre os módulos que compõem a arquitetura da Estrutura de
Entidades e como eles interagem uns com os outros e com você.
O capítulo 2 mostrará como construir um aplicativo a partir do zero, usando a Estrutura de Entidades. Aqui, você será apresentado ao aplicativo de
exemplo que usaremos ao longo do livro, e aprenderá a criar seu modelo e
gerar código automaticamente. Na última seção, você terá uma visão geral de
como ler dados de uma base de dados e persistir dados nela.
1
:!
Estrutura de Entidades
Este capítulo cobre
- DataSet e a abordagem clássica do ADO.NET
- A abordagem do modelo de objeto
- A incompatibilidade objeto/relacional
- A Estrutura de Entidades como solução
Quando você projeta um aplicativo, tem de decidir como acessar e representar dados. Esta decisão é provavelmente a mais importante que você tomará
em termos de desempenho do aplicativo e de facilidade de desenvolvimento
e manutenção. Em todos os projetos em que trabalhamos, o mecanismo de
persistência foi uma base de dados relacional. Apesar de algumas tentativas
de introduzir bases de dados de objetos, a base de dados relacional ainda é, e
será por muitos anos, o principal mecanismo de persistência.
Hoje em dia, as bases de dados relacionais oferecem todas as funcionalidades de que você precisa para persistir e recuperar dados. Você tem
tabelas para manter dados, vistas para organizá-los logicamente, de modo que
sejam mais fáceis de se consumir, procedimentos armazenados para abstrair
o aplicativo da estrutura da base de dados e melhorar o desempenho, chaves
H[WHUQDVSDUDUHODFLRQDUUHJLVWURVHPWDEHODVGLIHUHQWHVYHUL¿FDo}HVGHVHJXrança para evitar acesso não autorizado a dados sensíveis, a capacidade de
transparentemente encriptar e decriptar dados, e assim por diante. Há muito
mais sob a superfície, mas essas funcionalidades são as mais úteis para os
desenvolvedores.
4 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Quando você deve armazenar dados persistentemente, as bases de dados
relacionais são sua melhor opção. Por outro lado, quando você deve temporariamente representar dados num aplicativo, os objetos são o melhor caminho.
Funcionalidades como herança, encapsulamento, e sobreposição de métodos
SHUPLWHP XPD PHOKRU HVWLOR GH FRGL¿FDomR TXH VLPSOL¿FD R GHVHQYROYLmento, em comparação com a abordagem legada do DataSet.
Antes de nos aprofundarmos nos detalhes da Estrutura de Entidades, nós
usaremos as três primeiras seções deste capítulo para discutir como passar
da abordagem do DataSet para a abordagem baseada em objetos facilita o
desenvolvimento, e como essa maneira diferente de trabalhar leva à adoção de
uma ferramenta de mapeamento objeto/relacional (O/RM) como a Estrutura
de Entidades.
Quando você optar por usar objetos, tenha em mente que existem diferenças entre os paradigmas relacional e orientado por objetos, e que o papel da
Estrutura de Entidades é lidar com elas. Ela permite que o desenvolvedor se
concentre nos problemas funcionais e ignore, até certo ponto, o lado da persistência. Tais diferenças objeto/relacional são difíceis de superar. Na seção 1.4,
você descobrirá que há muito trabalho envolvido em acomodá-las. Então, as
últimas seções do capítulo mostrarão como a Estrutura de Entidades vem em
nosso auxílio para resolver o descompasso entre os paradigmas e oferecer uma
maneira conveniente de acessar dados.
$R ¿QDO GHVWH FDStWXOR YRFr WHUi XP ERP HQWHQGLPHQWR GR TXH p XPD
ferramenta de O/RM, para que ela é usada, e por que você deve sempre pensar
em usar uma quando criar um aplicativo que trabalhe com uma base de dados.
1.1 Introdução ao acesso a dados
Dados em tabelas são armazenados como uma lista de linhas, e cada linha
p FRPSRVWD GH FROXQDV (VWH H¿FLHQWH IRUPDWR WDEXODU WHP GLULJLGR R PRGR
dos desenvolvedores representarem dados em aplicativos por muitos anos.
Os desenvolvedores dos clássicos ASP e VB6 usam recordsets (conjuntos de
registros) para recuperar dados de bases de dados – o recordset é um contentor genérico que organiza os dados recuperados da mesma forma que eles
VmR¿VLFDPHQWHDUPD]HQDGRVHPOLQKDVHFROXQDV4XDQGRR1(7HVWUHRX
os desenvolvedores tiveram um novo objeto para manter dados na memória: o dataset (conjunto de dados). Embora este controle seja completamente
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 5
diferente do recordset que usávamos antes da era .NET, ele tem propósitos
similares e, mais importante, tem dados organizados da mesma maneira: em
linhas e colunas.
(PERUDHVWDUHSUHVHQWDomRVHMDH¿FLHQWHHPDOJXQVFHQiULRVHODFDUHFH
de muitas funcionalidades, como segurança de tipo, desempenho e gerenciabilidade. Discutiremos isso em mais detalhes quando falarmos de datasets, na
próxima seção.
No mundo do Java, uma estrutura como o dataset sempre existiu,
mas seu uso é agora desencorajado, exceto para aplicativos mais simples. No
mundo do .NET, nós estamos encarando o início desta tendência, também.
Você deve estar pensando: “Se eu não usar contentores de uso geral, o que uso
para representar os dados?” A resposta é fácil: objetos.
Objetos são superiores aos datasets em todos os casos, porque eles não
sofrem as limitações das estruturas de uso geral. Eles oferecem segurança de
WLSRDXWRFRPSOHWDPHQWRQR9LVXDO6WXGLRYHUL¿FDomRHPWHPSRGHFRPSLlação, melhor desempenho, e muito mais. Falaremos mais sobre objetos na
seção 1.2.
Os benefícios que você obtém com o uso de objetos têm um custo, resultante das diferenças entre o paradigma orientado por objetos e o modelo relacional usado pelas bases de dados. Há três diferenças notáveis:
Ŷ
Relacionamentos – numa estrutura tabular, você usa chaves externas com colunas; com classes, você usa referências a outras classes;
Ŷ
Igualdade – numa base de dados, os dados sempre distinguem uma
linha de outra, enquanto que no mundo dos objetos que você pode
ter dois objetos do mesmo tipo com os mesmos dados que ainda
sejam diferentes; e
Ŷ
Hereditariedade – o uso de herança é comum em linguagens orientadas por objetos, mas no mundo das bases de dados ela não é
suportada.
Isto apenas toca a superfície de um problema conhecido como incompatibilidade objeto/relacional, que será coberto na seção 1.4.
Neste panorama, o O/RM cuida da persistência do objeto. A ferramenta de
250¿FDHQWUHRFyGLJRGRDSOLFDWLYRHDEDVHGHGDGRVHFXLGDH¿FLHQWHGD
recuperação de dados e de sua transformação em objetos, rastreia as alterações
QRVREMHWRVHDVUHÀHWHQDEDVHGHGDGRV,VVRDVVHJXUDTXHYRFrQmRWHQKDGH
escrever quase 80 por cento do código de acesso a dados (essa é uma estimativa aproximada, baseada na nossa experiência).
6 - Entity Framework 4 - A Estrutura de Entidades - em Ação
1.2 Desenvolvendo aplicativos com estruturas no
estilo de bases de dados
Ao longo da última década, estivemos desenvolvendo aplicativos usando
o VB6, o ASP clássico, o Delphi e o .NET, e todas essas tecnologias usam
componentes ou objetos externos para acessar bases de dados e manter os
dados internamente. Ambas as tarefas são semelhantes em cada linguagem,
mas são especialmente similares na representação interna dos dados: os dados
são organizados em estruturas construídas sobre o conceito de linhas e colunas. O resultado é que os aplicativos controlam os dados da mesma forma que
eles são organizado na base de dados.
Por que diferentes fornecedores oferecem aos desenvolvedores o mesmo
modelo de programação? A resposta é simples: os desenvolvedores estão
acostumados com a representação tabular, e não precisam aprender mais nada
para serem produtivos. Além disso, essas estruturas genéricas podem conter
quaisquer dados, desde que eles possam ser representados em linhas e colunas. Potencialmente, mesmo dados provenientes de arquivos XML, de serviços web, ou de chamadas REST podem ser organizados desta forma.
Como resultado, os fornecedores desenvolveram um subconjunto de objetos que podem representar qualquer informação, sem que tenhamos de escrever uma única linha de código. Esses objetos são chamados contentores de
dados.
1.2.1 Usando datasets e leitores de dados como contentores
de dados
No início de nossa experiência com o .NET, muitos de nós usávamos
datasets e leitores de dados. Com algumas linhas de código, nós tínhamos um
objeto que poderia ser ligado a qualquer controle dirigido por dados e que,
no caso do leitor de dados, oferecia desempenho impressionante. Pelo uso de
um adaptador de dados em combinação com um dataset, nós tínhamos uma
estrutura completamente funcional para leitura e atualização de dados. Nunca
fomos tão produtivos. O Visual Studio também desempenhava seu papel. Seus
assistentes e a estreita integração com esses objetos nos dava a sensação de
que tudo poderia ser criado através do arrastar e soltar e da escrita de algumas
linhas de código.
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 7
Figura 1.1 - A tabela Order tem uma tabela
OrderDetail relacionada, que contém seus detalhes.
Vamos examinar um exemplo. Suponha que você tenha uma base de dados
FRPDVWDEHODV2UGHUH2UGHU'HWDLOFRPRPRVWUDGRQD¿JXUDHTXHYRFr
tenha de criar uma página web simples, onde todos os pedidos são mostrados.
O primeiro passo é criar uma conexão com a base de dados. Depois, você
SUHFLVDFULDUXPDGDSWDGRUH¿QDOPHQWHH[HFXWDUDFRQVXOWDFRORFDQGRRV
dados numa tabela de dados que você liga a um controle de lista. Esses passos
são mostrados na listagem seguinte.
$K?'
X
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlDataAdapter da = new SqlDataAdapter (“Select
* from order”, conn))
{
DataTable dt = new DataTable();
da.Fill(dt);
ListView1.DataSource = dt;
ListView1.DataBind();
}
}
8 - Entity Framework 4 - A Estrutura de Entidades - em Ação
YV
Using conn As New SqlConnection(connString)
Using da As New SqlDataAdapter(“Select * from order”,conn)
Dim dt As New DataTable()
da.Fill(dt)
ListView1.DataSource = dt
ListView1.DataBind()
End Using
End Using
Fazendo um pouco de refatoração, você consegue a conexão e o adaptador
numa única chamada a método, de modo que a quantidade de código é ainda
mais reduzida. Isso é tudo o que você precisa fazer para exibir os pedidos.
'HSRLVGHPH[HUFRPRSURWyWLSRRFOLHQWHPXGDDVHVSHFL¿FDo}HVHTXHU
ver os detalhes abaixo de cada pedido na lista. A solução se torna mais desa¿DGRUDSRUTXHYRFrSRGHRSWDUSRUGLIHUHQWHVDERUGDJHQV
Ŷ
Recuperar os dados da tabela Order e depois consultar os detalhes de cada pedido. Esta abordagem é, de longe, a mais fácil
GH FRGL¿FDU 3HOD LQWHUFHSWDomR GH TXDQGR XP SHGLGR p OLJDGR j
ListView, você pode consultar seus detalhes e exibi-los;
Ŷ
Recuperar os dados juntando as tabelas Order e OrderDetail. O
resultado é o produto cartesiano da junção entre as tabelas, e contém
WDQWDVOLQKDVTXDQWDVHVWmRQDWDEHOD2UGHU'HWDLO,VVRVLJQL¿FDTXH
o resultset (conjunto de resultados), como está, não pode ser passado a um controle, mas, primeiro, deve ser localmente processado;
e
Ŷ
Recuperar todas os pedidos e todos os detalhes de duas consultas distintas. Esta é, de longe, a melhor abordagem, porque realiza
apenas duas consultas à base de dados. Você pode ligar os pedidos
D XP FRQWUROH LQWHUFHSWDU TXDQGR FDGD SHGLGR p OLJDGR H ¿OWUDU
os detalhes na memória, para mostrar apenas aqueles relacionados
com o pedido atual.
Seja qual for o caminho que você escolher, há um ponto importante a considerar: você está ligado à estrutura da base de dados. Seu código é determinado por esta estrutura e pela maneira de você recuperar dados; cada escolha
leva a código diferente, e a mudança de táticas seria trabalhoso.
Vamos seguir em frente. Seu cliente, agora, precisa de uma página para
exibir dados de um único pedido, para que ele possa ser impresso. A página
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 9
deve conter rótulos para os dados do pedido e uma ListView para os detalhes. Supondo que você recupere os dados em dois comandos distintos, o
FyGLJR¿FDULDDVVLP
$K#?Z'
X
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand cm = new SqlCommand(“Select *
from order
ª where orderid = 1”, conn))
{
conn.Open();
using (SqlDataReader rd = cm.ExecuteReader())
{
rd.Read();
date.Text = ((DateTime)rd[“OrderDate”]).ToString();
shippingAddress.Text = rd[“ShippingAddress”].
ToString();
shippingCity.Text = rd[“ShippingCity”].ToString();
}
using (SqlDataReader rd = cm.ExecuteReader())
{
details.DataSource = rd;
details.DataBind();
}
}
}
YV
Using conn As New SqlConnection(connString)
Using cm As New SqlCommand(“Select * from order
ª
where orderid = 1”, conn)
conn.Open()
Using rd As SqlDataReader = cm.ExecuteReader()
rd.Read()
10 - Entity Framework 4 - A Estrutura de Entidades - em Ação
[date].Text = DirectCast(rd(“OrderDate”),
DateTime).ToString()
shippingAddress.Text = rd(“ShippingAddress”).ToString()
shippingCity.Text = rd(“ShippingCity”).ToString()
End Using
Using rd As SqlDataReader = cm.ExecuteReader()
details.DataSource = rd
details.DataBind()
End Using
End Using
End Using
A maneira como você acessa os dados é completamente insegura e genéULFD 3RU XP ODGR YRFr WHP JUDQGH ÀH[LELOLGDGH SRUTXH SRGH IDFLOPHQWH
escrever código genérico para implementar funções que não têm conheciPHQWRGRVQRPHVGRVFDPSRVGDWDEHODHTXHVHEDVHLDHPFRQ¿JXUDomR3RU
outro lado, você perde a segurança de tipos9RFrLGHQWL¿FDXPFDPSRHVSHFL¿FDQGRVHXQRPHXVDQGRXPDVWULQJVHRQRPHQmRHVWLYHUFRUUHWRYRFrVy
recebe uma exceção em tempo de execução.
Você não só perde controle sobre os nomes de campo, mas até mesmo dos
tipos de dados. Leitores de dados e de tabelas de dados (que são os itens que
contêm os dados num dataset) retornam os valores das colunas como tipos
Object (o tipo base do .NET), de forma que você precisa convertê-los para o
tipo correto (ou chamar o método ToString, também) . Este é um exemplo
da incompatibilidade objeto/relacional que mencionamos antes.
Agora que você viu o panorama do mundo dos contentores de dados genéricos, vamos investigar suas limitações e examinar por que esta abordagem
está sendo gradualmente descontinuada em aplicativos empresariais.
1.2.2 O problema do acoplamento forte
No exemplo anterior, você foi solicitado a determinar a melhor maneira
de exibir pedidos e detalhes numa grade. O que você precisa é de uma lista de
pedidos, onde cada pedido tem uma lista de detalhes associados.
Leitores de dados e tabelas de dados não permitem que você recupere
dados transparentemente, sem afetar o código da interface do usuário. Isto
VLJQL¿FDTXHVHXDSOLFDWLYRHVWiIRUWHPHQWHDFRSODGRjHVWUXWXUDGDEDVHGH
dados, e qualquer alteração nessa estrutura exige que seu código sofra alguma
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 11
adaptação pesada. Esta é provavelmente a razão mais importante para o uso
desses objetos ser desencorajado. Mesmo que você tenha os mesmos dados
em memória, a forma como eles são recuperados afeta a forma como eles são
representados internamente. Este é claramente um problema de busca, e é algo
que deve ser tratado no código de acesso a dados, não na interface do usuário.
Em muitos projetos em que nós trabalhamos, a base de dados servia apenas a um aplicativo, então os dados eram organizados de modo que o código
pudesse consumi-los facilmente. Este nem sempre é o caso. Às vezes, os aplicativos são construídos em cima de uma base de dados existente, e nada pode
VHUPRGL¿FDGRSRUTXHRXWURVDSOLFDWLYRVHVWmRXVDQGRDEDVHGHGDGRV(P
tais situações, você está ainda mais acoplado à base de dados e à organização
de seus dados, que pode ser extremamente diferente do que você esperaria.
Por exemplo, pedidos podem ser armazenados numa tabela e endereços de
entrega noutra. O código de acesso a dados poderia reduzir o impacto, mas o
problema da busca permaneceria.
E o que acontece quando o nome de uma coluna muda? Isso acontece
com frequência quando um aplicativo está em desenvolvimento. O resultado
pTXHRFyGLJRGDLQWHUIDFHSUHFLVDVHUDGDSWDGRSDUDUHÀHWLUHVVDPXGDQoD
seu código é muito frágil, porque uma busca e substituição é a única maneira
GHDWLQJLUHVWHREMHWLYR9RFrSRGHPLWLJDURSUREOHPDPRGL¿FDQGRR64/
e adicionando um apelido para manter o nome antigo no resultset, mas isso
causa mais confusão e logo se transforma num novo problema.
26789:;<=>@6@AB=EF8G7=B=
Para recuperar o valor de uma coluna armazenada num leitor de dados ou
numa tabela de dados, você normalmente se refere a ela usando uma string constante. O código que usa uma tabela de dados tipicamente se parece com este:
X
object shippingAddress = orders.Rows[0][“ShippingAddress”];
YV
Dim shippingAddress As Object = orders.Rows(0)
(“ShippingAddress”)
A variável shippingAddress é do tipo System.Object, então ela
potencialmente pode conter qualquer tipo de dados. Você pode saber que ela
12 - Entity Framework 4 - A Estrutura de Entidades - em Ação
contém um valor string, mas para usá-la como uma string, você tem de explicitamente realizar uma conversão:
X
string shippingAddress = (string)orders.Rows[0]
[“ShippingAddress”];
string shippingAddress = orders.Rows[0]
[“ShippingAddress”].ToString();
YV
Dim shippingAddress As String = _
DirectCast(orders.Rows(0)(“ShippingAddress”), String)
Dim shippingAddress As String = _
orders.Rows(0)(“ShippingAddress”).ToString()
A conversão é custosa, tanto em termos de desempenho quanto de uso de
memória, porque a conversão de um tipo de valor para um tipo de referência e
vice-versa faz com que ocorra empacotamento (boxing) e desempacotamento
(unboxing). Em alguns casos, a conversão pode exigir o uso da interface
IConvertible, que faz uma conversão interna.
Leitores de dados têm uma vantagem sobre tabelas de dados. Eles ofereFHPPpWRGRVWLSL¿FDGRVSDUDDFHVVRDFDPSRVVHPDQHFHVVLGDGHGHFRQYHUsões explícitas. Tais métodos recebem um parâmetro inteiro que representa
o índice da coluna na linha. Leitores de dados também têm um método que
retorna o índice de uma coluna, dado seu nome, mas seu uso tende a desordenar o código e está sujeito a erros de digitação:
X
string address = rd.GetString(rd.GetOrdinal
(“ShippingAddress”));
string address = rd.GetString(rd.GetOrdinal
(“ShipingAdres”)); //exceção
YV
Dim address As String = _
rd.GetString(rd.GetOrdinal(“ShippingAddress”))
Dim address As String = _
rd.GetString(rd.GetOrdinal(“ShipingAdres”)) ‘exceção
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 13
O problema resultante de alterações de nomes de colunas, discutido na
seção anterior, envolve até a perda de controle em tempo de compilação. Não
é desejável descobrir, em tempo de execução, que um nome de coluna mudou
ou que você digitou incorretamente o nome da coluna. Os compiladores não
podem ajudar a evitar tais problemas, porque eles não têm conhecimento de
qual é o nome da coluna.
1.2.4 O problema do desempenho
O DataSet é provavelmente uma das estruturas mais complexas da biblioteca de classes .NET. Ele contém uma ou mais instâncias de
DataTable, e cada uma delas tem uma lista de objetos DataRow composta
de um conjunto de objetos DataColumn. Uma DataTable pode ter uma
chave primária composta de uma ou mais colunas e pode declarar que determinadas colunas têm um relacionamento de chave externa com colunas em
outra DataTable. Colunas suportam controle de versãoRTXHVLJQL¿FDTXH
se você alterar o valor, tanto o valor antigo quanto o novo serão armazenados
na coluna para realização de YHUL¿FDo}HVGHFRQFRUUrQFLD. Para enviar atualizações à base de dados, você tem de usar uma classe DbDataAdapter (ou,
mais precisamente, uma de suas classes derivadas), que é ainda outro objeto.
Embora essas funcionalidades sejam muitas vezes completamente inúteis
e sejam ignoradas pelos desenvolvedores, DataSet cria internamente uma
FROHomRYD]LDGHVVHVREMHWRV,VVRSRGHVHUXPLQVLJQL¿FDQWHGHVSHUGtFLRGH
recursos para um aplicativo independente, mas num ambiente multiusuário,
com milhares de requisições, como um aplicativo web, isso se torna inaceitáYHOeLQ~WLORWLPL]DURGHVHPSHQKRGDEDVHGHGDGRVD¿QDURVtQGLFHVPRGL¿FDUR64/DGLFLRQDUGLFDVHDVVLPSRUGLDQWHVHYRFrGHVSHUGLoDUHFXUVRV
criando estruturas de que não precisa.
Em comparação, o DataReader foi construído para cenários diferentes.
Uma DataTable carrega na memória todos os dados lidos da base de dados,
mas muitas vezes você não precisa de todos os dados na memória, e poderia,
ao invés, buscá-los de registro em registro da base de dados. Outra situação
é em atualizações de dados; muitas vezes, você precisa ler dados, mas não
precisa atualizá-los. Nesses casos, algumas funcionalidades, como controle
de versão de linha, são inúteis. DataReader é a melhor escolha em tais
situações, porque ele recupera dados de uma forma somente para leitura (mais
rápida). Embora aumente o desempenho, o DataReader ainda pode sofrer
dos problemas de conversão de DataSet, mas esta perda de tempo é menor
que o ganho que você obtém do seu uso.
14 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Todos estes problemas podem parecer excessivos, mas muitos aplicativos
SRUDtDIRUDVHEHQH¿FLDPGRXVRGHHVWUXWXUDVGRWLSRGHEDVHGHGDGRV$LQGD
mais serão desenvolvidos no futuro usando esses objetos sem problemas. No
entanto, em projetos de classe empresarial, onde a base de código é grande e
YRFrSUHFLVDGHPDLVFRQWUROHHÀH[LELOLGDGHYRFrSRGHH[SORUDURSRGHUGD
programação orientada por objetos e usar classes para organizar seus dados.
1.3 Usando classes para organizar dados
Estamos vivendo na era da orientação por objetos. As linguagens procedimentais ainda existem, mas são restritas a ambientes particulares. Por exemplo, o COBOL ainda é necessário para aplicativos que rodam em arquiteturas
de mainframe.
O uso de classes é uma escolha natural para a maioria dos aplicativos,
hoje. Classes são a base da programação orientada por objetos. Eles facilmente
representam dados, executam ações, publicam eventos, e assim por diante. Do
ponto de vista da organização de dados, as classes expressam os dados através
GHPpWRGRVHSURSULHGDGHVTXHQR¿QDOVmRPpWRGRVHVSHFLDLV
Usando classes, você pode escolher sua representação interna de dados
sem se preocupar com a forma como eles serão persistidos – você não precisa
saber de nada sobre o mecanismo de armazenamento. Este poderia ser uma
base de dados, um serviço web, um arquivo XML, ou qualquer outra coisa.
A representação de dados sem que se tenha qualquer conhecimento do mecanismo de armazenamento é conhecida como ignorância da persistência, e as
classes utilizadas nesse cenário são chamadas de POCOs (sigla em inglês para
antigos objetos CLR simples).
O uso de classes oferece vários benefícios que são particularmente importantes em aplicações empresariais:
Ŷ
;<% – você não precisa mais converter cada coluna de
uma linha para obter seu valor com o tipo correto (ou, pelo menos,
você não tem de fazê-lo no código da interface);
Ŷ
)<%<% – as classes expõem as propriedades para acessar dados; elas não usam um método genérico
ou indexador. Se você entrar incorretamente o nome de uma propriedade, obterá imediatamente um erro de compilação. Você não
precisa mais rodar o aplicativo para encontrar erros de digitação;
Ŷ
Facilidade de desenvolvimento – Editores como o Visual
Studio oferecem o IntelliSense para acelerar o desenvolvimento.
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 15
Ŷ
O IntelliSense oferece dicas ao desenvolvedor sobre propriedades, eventos e métodos expostos por uma classe. Mas se você usar
DataSet, os editores não poderão ajudá-lo de nenhuma maneira,
porque as colunas serão recuperadas usando strings, que não estão
sujeitas ao IntelliSense; e
Interface independente do armazenamento – Você não tem de moldar as classes para acomodar a estrutura da base de dados, o que lhe
GiRPi[LPRGHÀH[LELOLGDGH$VFODVVHVWrPVXDSUySULDHVWUXWXUD
e embora muitas vezes esta seja similar à da tabela a que estão relacionadas, ela não precisa sê-lo. Você não tem mais de se preocupar
com a organização da base de dados e a recuperação de dados, porque você código para classes. Os detalhes da recuperação de dados
VmRGHOHJDGRVDXPDSDUWHHVSHFt¿FDGRDSOLFDWLYRHRFyGLJRGD
interface permanece sempre o mesmo.
Para dar uma olhada em estes conceitos na prática, vamos refazer o exemplo da seção anterior.
1.3.1 Usando classes para representar dados
Vamos partir novamente do zero. O cliente quer exibir os pedidos numa
grade. O primeiro passo é criar uma classe Order para conter os dados dos
SHGLGRVFRPRPRVWUDGRQD¿JXUD
A classe Order tem a mesma estrutura que a tabela relacionada da base
de dados. A única diferença óbvia, aqui, é que você tem tipos .NET (String,
Int32, DateTime) em vez de tipos de bases de dados (int, varchar, date).
Figura 1.2 - A classe Order contém os dados da tabela Order.
16 - Entity Framework 4 - A Estrutura de Entidades - em Ação
O segundo passo é criar uma classe com um método que lê dados da base
de dados e os transforma em objetos, como na listagem seguinte. A classe
FRQWHQWRUD IUHTXHQWHPHQWH ¿FD QXPD PRQWDJHP VHSDUDGD FRQKHFLGD FRPR
camada de dados.
$K/'
X
public List<Order> GetOrders()
{
using (SqlConnection conn = new SqlConnection
(connString))
{
using (SqlCommand comm = new SqlCommand(“select *
from orders”, conn))
{
conn.Open();
using(SqlDataReader r = comm.ExecuteReader())
{
List<Order> orders = new List<Order>();
while (rd.Read())
{
orders.Add(
new Order
{
CustomerCode = (string)rd[“CustomerCode”],
OrderDate = (DateTime)rd[“OrderDate”],
OrderCode = (string)rd[“OrderCode”],
ShippingAddress = (string)
rd[“ShippingAddress”],
ShippingCity = (string)rd[“ShippingCity”],
ShippingZipCode = (string)
rd[“ShippingZipCode”],
ShippingCountry = (string)
rd[“ShippingCountry”]
}
);
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 17
}
return orders;
}
}
}
}
...
ListView1.DataSource = new OrderManager().GetOrders();
ListView1.DataBind();
YV
Public Function GetOrders() As List(Of Order)
Using conn As New SqlConnection(connString)
Using comm As New SqlCommand(“select
* from orders”, conn)
conn.Open()
Using r As SqlDataReader = comm.ExecuteReader()
Dim orders As New List(Of Order)()
While rd.Read()
orders.Add(New Order() With {
.CustomerCode = DirectCast(rd
(“CustomerCode”), String),
.OrderDate = DirectCast(rd(“OrderDate”),
DateTime),
.OrderCode = DirectCast(rd(“OrderCode”),
String),
.ShippingAddress = DirectCast
(rd(“ShippingAddress”), String),
.ShippingCity = DirectCast
(rd(“ShippingCity”), String),
.ShippingZipCode = DirectCast
(rd(“ShippingZipCode”), String),
.ShippingCountry = DirectCast
(rd(“ShippingCountry”), String)
})
End While
Return orders
End Using
End Using
18 - Entity Framework 4 - A Estrutura de Entidades - em Ação
End Using
End Function
...
ListView1.DataSource = New OrderManager().GetOrders()
ListView1.DataBind()
“Que quantidade enorme de código!” Esta é, muitas vezes, a primeira reação das pessoas ao código da listagem 1.3. E elas estão certas; é muito código,
particularmente se você compará-la com a listagem 1.1, que usa um dataset.
Se seu aplicativo tiver de mostrar dados simples como estes, a abordagem do
GDWDVHWpPDLVGHVHMiYHO0DVTXDQGRDVFRLVDV¿FDPFRPSOH[DVDVFODVVHV
ajudam muito mais.
Vamos dar uma olhada na próxima funcionalidade exigida: a exibição de
um único pedido num formulário. Após o pedido ser recuperado, a exibição de
suas propriedades usando-se classes é muito mais direta:
X=
shippingAddress.Text = order.ShippingAddress;
shippingCity.Text = order.ShippingCity;
YV
shippingAddress.Text = order.ShippingAddress
shippingCity.Text = order.ShippingCity
O último passo é a exibição, numa grade, dos pedidos e dos detalhes relacionados. Fazer isso requer um conhecimento profundo, porque isso introduz
o conceito de modelos. Você não pode representar pedidos e detalhes numa
única classe – você tem de usar duas classes separadas da mesma maneira que
o faz com tabelas. Na próxima seção, discutiremos esta técnica.
1.3.2 De uma única classe ao modelo de objeto
Agora, você viu como desenvolver uma única classe isolada e como instanciá-la usando dados de uma base de dados, mas o poder real vem quando
você cria mais classes e começa a ligá-las umas às outras (por exemplo,
quando você cria uma classe OrderDetail que contém dados da tabela
OrderDetail).
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 19
Numa base de dados, o relacionamento entre um pedido e suas linhas de
detalhes é descrito pelo uso de uma restrição de chave externa entre a coluna
OrderId da tabela Ordem e a coluna OrderId da tabela OrderDetail. Do ponto
de vista do design de uma base de dados, esta é a abordagem correta.
No mundo orientado por objetos, você tem de seguir um outro caminho.
Não há sentido em se criar uma classe OrderDetail e dar-lhe uma propriedade OrderId. A melhor solução é tirar vantagem de uma característica peculiar das classes: elas podem ter propriedades cujo tipo é uma classe
GH¿QLGD SHOR XVXiULR ,VWR VLJQL¿FD TXH D FODVVH Order pode guardar uma
referência a uma lista de objetos OrderDetail, e a classe OrderDetail
pode ter uma referência a Order.
Quando cria esses relacionamentos, você está começando a criar um
modelo de objeto. Um modelo de objeto é um conjunto de classes relacionadas
entre si que descrevem os dados consumidos por um aplicativo.
O poder real do modelo de objeto surge quando você precisa exibir pedidos e seus detalhes relacionados numa única grade. Na seção 1.2.1, houve
um problema de busca com um espectro de soluções. Cada uma era diferente,
PDVRTXHpSLRUpTXHFDGDXPDH[LJLDXPHVWLORGHFRGL¿FDomRGLIHUHQWHQD
interface.
8VDQGRFODVVHVRFyGLJRGHVXDLQWHUIDFH¿FDFRPSOHWDPHQWHLVRODGRGRV
problemas de busca, porque ele não mais se preocupa com a base de dados.
8PDSDUWHHVSHFt¿FDGRDSOLFDWLYREXVFDUiRVGDGRVHUHWRUQDUiREMHWRVeDt
que a funcionalidade de interface independente de armazenamento do uso de
classes entra em cena.
'-(!(0)
Os padrões de Modelo de Objeto e de Modelo de Domínio são muitas vezes consideradas como se referindo à mesma coisa. Eles podem,
inicialmente, parecer exatamente o mesmo, porque ambos carregam
dados extraídos do armazenamento. Mas, depois de se aprofundar um
pouco, você perceberá que eles têm diferenças: o modelo de objeto contém apenas dados, enquanto que o modelo de domínio contém dados e
expõe comportamentos.
A classe Order que estivemos examinando é uma expressão perfeita
de um modelo de objeto. Ela tem propriedades que guardam dados,
e nada mais. Você pode adicionar uma propriedade computada que
reporte o endereço completo pela combinação dos valores de outras
20 - Entity Framework 4 - A Estrutura de Entidades - em Ação
propriedades, mas este seria um método auxiliar. Ele não acrescentaria
nenhum comportamento à classe.
Se você quiser passar de um modelo de objeto para um modelo
de domínio, terá de adicionar comportamento à classe. Para entender
melhor o conceito de comportamento, suponha que você precise saber
se um pedido excede a quantidade total permitida. Com um modelo de
objeto, você tem de construir um método noutra classe. Neste método,
você chama a base de dados para recuperar o quantidade máxima permitida, e depois a compara com a quantidade do pedido. Se você optar
por um modelo de domínio, por outro lado, poderá adicionar um método
,V&RUUHFWjFODVVH2UGHUHUHDOL]DUOiDYHUL¿FDomR'HVWDIRUPDYRFr
estará adicionando comportamento e expressividade à classe Order.
A criação e manutenção de um modelo de domínio não é nada fácil.
Ele força o arquiteto de software a fazer escolhas a respeito do design
do aplicativo. Em particular, as classes devem ser responsáveis por sua
própria validação e devem sempre estar num estado válido. (Por exemSORXPSHGLGRGHYHVHPSUHWHUXPFOLHQWHUHODFLRQDGR(VVDVYHUL¿cações podem contribuir para o inchaço do código nas classes; então,
para evitar confusão, você pode ter de criar outras classes que sejam
responsáveis pela validação, e mantê-las no modelo de domínio.
Os detalhes dos padrões de Modelo de Objeto e de Modelo de
Domínio estão fora do escopo deste livro e não serão cobertos, mas há
muitos livros focando neste assunto e em todas as suas implicações.
Recomendamos o Domain Driven Design, de Eric Evans (Addison-Wesley Professional, 2004). Discutiremos o padrão de Modelo de
Domínio e a Estrutura de Entidades no capítulo 14.
2H[HPSORTXHH[DPLQDPRVDWpDTXLpPXLWRVLPSOL¿FDGR9RFrGHYHWHU
percebido que a classe Order tem uma propriedade CustomerId e que
a classe OrderDetail tem uma propriedade ProductId. Num projeto
completo, você também teria as classes Customer e Product. Provavelmente, um cliente tem uma lista de descontos aplicáveis com base em alguma
condição, e um produto pertence a uma ou mais categorias. A criação de um
modelo de objeto forte exige um alto grau de conhecimento, disciplina, e uma
boa quantidade de prática.
À primeira vista, pode parecer que um mapeamento um-para-um entre
FODVVHVHWDEHODVGDEDVHGHGDGRVVHMDVX¿FLHQWH$SURIXQGDQGRPDLVSRUpP
o paradigma orientado por objetos tem muito mais expressividade e um conjunto diferente de funcionalidades em comparação com a estrutura da base
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 21
de dados. Herança, relacionamentos muitos-para-muitos e grupos lógicos de
GDGRVVmRWRGRVFDUDFWHUtVWLFDVTXHLQÀXHQFLDPQDIRUPDGHYRFrSURMHWDUXP
modelo. Mais importante ainda, tais características criam uma incompatibilidade entre a representação relacional e o modelo; na literatura, este problema
é conhecido como incompatibilidade objeto/relacional, e é discutido na próxima seção.
1.4 Aprofundando as diferenças entre objeto e
relacional
Entender as diferenças entre os mundos orientado por objetos e relacional
é importante, porque elas afetam a maneira de você projetar um objeto ou
modelo de domínio e a base de dados.
A incompatibilidade pode ser esmiuçada em diferentes partes relativas a
tipos de dados, associações, granularidade, herança e identidade, e, nas seções
seguintes, nós examinaremos cada uma delas por vez. Para melhor ilustrar essa
incompatibilidade, faremos uso do exemplo apresentado em seções anteriores.
1.4.1 A incompatibilidade de tipos de dados
A incompatibilidade de tipos de dados se refere às diferentes representações e restrições de dados que são usadas nos mundos de objetos e relacional.
Quando você adiciona uma coluna a uma tabela, numa base de dados, tem
de decidir que tipo de dado atribuir a ela. Qualquer base de dados moderna
suporta char, varchar, int, data, decimal, e assim por diante. Quando
se trata de classes, a situação é diferente. Os tipos int e bigint de bases de
dados se encaixam naturalmente nos tipos .NET Int32 e Int64, mas outros
tipos das bases de dados não têm uma correspondência exata no .NET.
Na base de dados, quando você sabe que o valor de uma coluna tem um
FRPSULPHQWRPi[LPRYRFrGH¿QHHVVDUHVWULomRQDFROXQDSDUDIRUoDUDUHJUD
funcional. Isto é particularmente desejável quando a base de dados serve
a vários aplicativos, e o seu não é o único que atualiza dados. No .NET, o
varchar não existe. O tipo mais próximo de varchar é String, mas
ele não suporta nenhuma limitação declarativa ao seu comprimento (ele pode
FRQWHU*%GHGDGRV6HYRFrTXLVHUYHUL¿FDUVHRYDORUGDString não
p PDLV FRPSULGR TXH R HVSHUDGR WHUi GH LPSOHPHQWDU HVWD YHUL¿FDomR QR
22 - Entity Framework 4 - A Estrutura de Entidades - em Ação
GH¿QLGRUGDSURSULHGDGHRXFKDPDUXPPpWRGRGHYHUL¿FDomRDQWHVGHHQYLDU
os dados de volta à base de dados.
Outro exemplo desta incompatibilidade envolve dados binários. Toda
base de dados aceita dados binários, mas a coluna que contém os dados não
sabe nada sobre o que eles representam. Eles podem ser um arquivo texto ou
PDF, uma imagem, e assim por diante. No .NET, você poderia representar
tal coluna usando um Object, mas isso não teria sentido, porque você sabe
perfeitamente bem que tipo de dado armazenou na coluna binária. Se o valor
for um arquivo, você poderá usar uma propriedade Stream, enquanto que o
tipo Image é sua melhor opção para imagens.
Um último exemplo da diferença de tipos de dados surge quando você usa
datas. Dependendo do fornecedor e da versão da base de dados, você tem muitos tipos de dados que pode usar para armazenar uma data. Por exemplo, até a
versão 2005 do SQL Server, você tinha DateTime e SmallDateTime. O
SQL Server 2008 introduziu mais dois tipos de dados: Date e Time. Como
você pode imaginar, o primeiro contém apenas uma data, e o segundo apenas
um horário. No .NET, você tem apenas uma classe DateTime que representa
tanto uma data quanto um horário. Tratar esta incompatibilidade não é difícil,
mas requer um pouco de disciplina quando da instanciação do objeto a partir
de dados da base de dados e vice-versa.
Como você pode ver, a incompatibilidade de tipos de dados é trivial e não
faz com que os desenvolvedores percam o sono. Mas ela existe, e é algo de
que você deve cuidar.
A segunda diferença, que já surgiu na seção 1.2, é a associação entre as
classes. As bases de dados usam chaves externas para representar relacionamentos, enquanto que aplicativos orientados por objetos usam referências a
outros objetos. Na próxima seção, nós nos aprofundaremos neste assunto.
1.4.2 A incompatibilidade de associação
Ao falar sobre as associações, a maior incompatibilidade entre os mundos relacional e de objetos está em como os relacionamentos são mantidos.
Tabelas de bases de dados são relacionadas usando-se um mecanismo que é
diferente do que é usado por classes. Vamos examinar como a cardinalidade
dos relacionamentos é tratada nos dois mundos.
RELACIONAMENTOS UM-PARA-UM
A tabela Order contém todos os dados dos pedidos. Mas suponha que
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 23
o aplicativo precise ser melhorado, e que uma coluna adicional tem de ser
acrescentada à tabela Order. Isto pode, inicialmente, parecer uma pequena
melhora, porque a adição de uma coluna não é tão perigosa. Mas é mais sério
que isso. Pode haver muitos aplicativos que dependam dessa tabela, e você
não quer se arriscar a introduzir bugs. A alternativa é criar uma nova tabela
que tenha OrderId como chave primária e que contenha as novas colunas.
Do lado da base de dados, essa é uma troca razoável, mas a repetição de
tal design no modelo de objeto não teria sentido. A melhor maneira de agir é
adicionar propriedades à classe OrderFRPRPRVWUDGRQD¿JXUD
Figura 1.3 - A tabela Order2 contém colunas para os novos dados e está
relacionada com a tabela Order. No modelo de objeto, não há
nenhuma classe nova – apenas uma nova propriedade na classe Order.
O método que interage com a base de dados tratará as diferenças entre os
dois esquemas. Tal método não é de forma alguma complicado; ele realiza
uma junção entre as duas tabelas e atualiza os dados em ambas para tratar a
incompatibilidade:
Select a.*, b.* from Orders a join Order2 on
(a.orderid = b.orderid)
Esta diferença de associação leva à incompatibilidade de granularidade,
que será discutida posteriormente, nesta seção.
RELACIONAMENTOS UM-PARA-MUITOS
Você já viu um relacionamento um-para-muitos quando nós ligamos
detalhes a um pedido. Numa base de dados, a tabela que representa o lado
“muitos” do relacionamento contém a chave primária da tabela mestra. Por
exemplo, a tabela OrderDetail contém uma coluna OrderId que liga o detalhe
a seu pedido. No jargão da bases de dados, esta coluna é chamada de chave
externa.
Por natureza, as associações de base de dados são únicas e bidirecionais.
24 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Por únicasTXHUHPRVGL]HUTXHYRFrVyWHPGHGH¿QLURUHODFLRQDPHQWRGH
XPODGRRODGR2UGHU'HWDLOYRFrQmRSUHFLVDGH¿QLUQDGDQDWDEHOD2UGHU
BidirecionaisVLJQL¿FDTXHPHVPRTXHYRFrPRGL¿TXHDSHQDVXPODGRYRFr
terá automaticamente relacionado o registro mestre aos seus detalhes e um
detalhe ao seu mestre. Isto é possível porque o SQL permite que você realize
junções entre tabelas para obter o pedido relacionado a um detalhe e todos os
detalhes relacionados a um pedido.
No mundo orientado por objetos, tal automatismo não existe porque tudo
deve ser explicitamente declarado. A classe OrderDetail contém uma
referência ao pedido através de sua propriedade Order, e esse comportaPHQWRpVLPLODUjEDVHGHGDGRV$GLIHUHQoDUHDOpTXHYRFrSUHFLVDPRGL¿FDU
também a classe Order, adicionando uma propriedade (OrderDetails)
que contém uma lista de objetos OrderDetail que representam os detalhes
GRSHGLGR1D¿JXUDYRFrSRGHYHUHVWHUHODFLRQDPHQWR
Figura 1.4 - O relacionamento entre Order e OrderDetail
no modelo de objeto é expressado com propriedades.
Até aqui, você tem tratado dos pedidos e seus detalhes. Agora, vamos
passar ao tratamento de produtos e seus fornecedores. Um produto pode ser
comprado de mais de um fornecedor e um único fornecedor pode vender
muitos produtos. Isto leva a uma associação muitos-para-muitos.
RELACIONAMENTOS MUITOS-PARA-MUITOS
O relacionamento muitos-para-muitos representa uma associação em que cada
XPDGDVSRQWDVWHPXPDUHODomRP~OWLSODFRPDRXWUD,VWRVLJQL¿FDTXHQmRKi
relacionamento mestre-detalhe entre tabelas – ambas estão no mesmo nível.
Por exemplo, se você tiver as tabelas Product e Supplier, não poderá
expressar o relacionamento entre elas simplesmente criando uma chave
externa numa delas. A única maneira de ligá-las é não ligá-las de forma alguma.
Em vez disso, você cria uma tabela intermediária, conhecida como tabela
de ligação, que contém a chave primária de ambas as tabelas. As tabelas
Product e Supplier contêm apenas seus próprios dados, enquanto que a tabela
de ligação contém o relacionamento entre elas. Desta forma, as duas tabelas
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 25
principais não estão diretamente conectados, mas dependem de uma terceira,
que tem chaves externas.
Figura 1.5 - Na base de dados, as tabelas Product e Supplier estão relacionadas através da tabela ProductSupplier. No modelo, as classes Product e Supplier estão diretamente relacionadas pelo uso de propriedades.
Num modelo de objeto, o conceito de tabela de ligação não existe, porque o relacionamento é representado como uma lista de referências à outra
classe de ambos os lados. Como você tem as tabelas Product e Supplier na
base de dados, você cria as classes Product e Supplier no modelo. Na
classe Product, você adiciona uma propriedade Suppliers que contém
uma lista de objetos Supplier representando aqueles que vendem o produto. Da mesma forma, na classe Supplier você adiciona uma propriedade
Products que contém uma lista de objetos Product que representa os
SURGXWRVYHQGLGRVSHORIRUQHFHGRU$¿JXUDPRVWUDWDLVDVVRFLDo}HV
Como os relacionamentos um-para-um, os muitos-para-muitos são uma
das causas do problema de granularidade que aparece no modelo de objeto. A
outra causa do problema de granularidade é coberto na próxima seção.
1.4.3 A incompatibilidade de granularidade
O problema da granularidade se refere à diferença no número de classes
em comparação com o número de tabelas na base de dados. Você já viu que,
dependendo dos tipos de relacionamentos, você pode acabar com as menos
classes que tabelas. Agora, vamos explorar uma outra causa da incompatibilidade de granularidade: os tipos de valores.
26 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Vamos voltar ao nosso exemplo. A tabela Order tem um endereço de
entrega que é dividido em quatro colunas: endereço, cidade, CEP e país.
Suponha que você precise tratar de outro endereço, digamos, o endereço de
cobrança, e que você decida adicionar mais quatro colunas à tabela Order, de
IRUPDTXHHODVHSDUHoDFRPDTXHpPRVWUDGDQD¿JXUD
A classe Order já tem quatro propriedades para o endereço de entrega,
assim, adicionar outras propriedades não será problema. Mas, embora isso
funcione perfeitamente, essas novas propriedades fazem a classe crescer, tornando-a mais difícil de entender. Além do mais, clientes e fornecedores têm
um endereço, a loja tem um endereço, e talvez outras classes também tenham
endereços. Classes são reutilizáveis, então, não seria bom criar uma classe
AddressInfo e reutilizá-la em todo o modelo?
Figura 1.6 - Um excerto da nova tabela Order com o
novo campo de endereço de cobrança
&RP XP SRXFR GH UHPRGHODomR YRFr SRGH PRGL¿FDU D FODVVH Order
para remover as propriedades relacionadas a endereços e adicionar mais duas:
ShippingAddress e BillingAddress. O código depois da remodelação se parece com este.
$KGJAddressInfo e Order
X
public class AddressInfo
{
public string Address { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 27
}
public class Order
{
public Address ShippingAddress { get; set; }
public Address BillingAddress { get; set; }
}
YV
Public Class AddressInfo
Public Property Address() As String
Public Property City() As String
Public Property ZipCode() As String
Public Property Country() As String
End Class
Public Class Order
Public Property ShippingAddress() As Address
Public Property BillingAddress() As Address
End Class
Como você pode ver, o código, depois da remodelação, é fácil de entender.
*?=
Temos visto soluções em que a base de dados foi excessivamente
normalizada. Os endereços foram passados para uma tabela diferente,
com sua própria identidade, e chaves externas foram usadas para ligar
a tabela do cliente à do endereço. Do ponto de vista de um designer
purista de bases de dados, esta abordagem pode ser correta, mas, na
prática, ela não funciona tão bem quanto se as colunas fossem armazenadas na tabela de clientes. É muito provável que você precise de
informações de endereço toda vez que recuperar um pedido, de modo
que todo acesso exigirá uma junção com a tabela de endereços.
Este design pode ou não ter otimizado o projeto geral da base de
dados, mas, do ponto de vista de um desenvolvedor, ele foi uma escolha
difícil. Este design também afetou o design do modelo de objeto. A classe
AddressInfo era originalmente um mero contentor de dados, mas
foi transformada numa entidade que tem sua própria correspondência
com uma tabela da base de dados. As consequências foram um maior
número de linhas de código para manter a nova tabela na base de dados,
e um desempenho mais lento porque os comandos SQL aumentaram
28 - Entity Framework 4 - A Estrutura de Entidades - em Ação
DWXDOL]DU XP FOLHQWH VLJQL¿FDYD DWXDOL]DU VHXV GDGRV SHVVRDLV H GH
endereço). Quem avisa, amigo é.
Outra causa dos diferentes níveis de granularidade é a funcionalidade de
herança da OOP. Num modelo, é comum criar-se uma classe base e deixar que
outras classes herdem dela. Em bases de dados relacionais, porém, o conceito
de herança não existe, então, você tem de usar alguma alternativa para tratar
tais cenários, como veremos em seguida.
1.4.4 A incompatibilidade de herança
A incompatibilidade de herança se refere à impossibilidade de representar
grafos de herança numa base de dados. Vamos voltar ao exemplo, para ver por
que esta diferença representa um problema.
9DPRV UH¿QDU R PRGHOR GH REMHWR SDUD DGLFLRQDU D FODVVH Customer,
e faremos com que ela e a classe Supplier herdem de Company. É altamente provável que essas entidades compartilhem colunas, tais como endereço, número de contribuinte, nome, e assim por diante, portanto, o uso de
KHUDQoDpDPDQHLUDPDLVQDWXUDOGHSURMHWDUWDLVFODVVHV$¿JXUDPRVWUD
essas classes.
Figura 1.7 - As classes Supplier e Customer herdam de Company.
Numa base de dados relacional, você não pode simplesmente declarar
uma tabela Customer e dizer que ela herda de outra tabela. Não é assim que
a organização relacional funciona. Você pode criar uma única tabela que contenha os dados tanto do cliente quanto do fornecedor, ou criar uma para cada
tipo. Seja qual for a sua decisão, haverá uma incompatibilidade entre a base
de dados e o modelo.
No modelo, você tem uma classe Product. Uma loja pode vender diferentes tipos de produtos, tais como sapatos, camisas, equipamento de golfe,
equipamento de natação, e assim por diante. Todos estes produtos compartilham alguns tipos básicos de dados, como preço e cor, e também têm outras
LQIRUPDo}HVTXHVmRHVSHFt¿FDVGHFDGDSURGXWR
0HVPRQHVWHFDVRDKHUDQoDYHPHPVHXDX[tOLR3DUDUHÀHWLUHVVDVLWXação, você escreve uma classe Product, e depois cria uma classe para cada
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 29
SURGXWR HVSHFt¿FR 2 PDLRU SUREOHPD VXUJH TXDQGR YRFr SURMHWD D FODVVH
OrderDetail. Nessa classe, você precisará de uma propriedade que indique a que produto o detalhe se refere; esta propriedade será do tipo Product,
mesmo que, em tempo de execução, a instância concreta do objeto possa ser
do tipo Shoes, Shirts, ou de qualquer outro tipo que herde de Product.
$¿JXUDPRVWUDHVWDKLHUDUTXLDGHKHUDQoDQRPRGHOR
Este tipo de associação é conhecido como >, e é absolutamente
impossível representá-lo nativamente numa base de dados. Além disso, para
recuperar o produto relacionado a um detalhe de pedido, você precisa de uma
FRQVXOWDSROLPyU¿FD, que não é suportada numa base de dados.
Felizmente, após anos de experiência, os desenvolvedores têm encontrado
uma maneira de usar uma combinação de design de base de dados, sentenças
64/HFyGLJRSDUDVLPXODURHIHLWRGHXPDFRQVXOWDSROLPyU¿FD,VVRVLJQL¿FD
que você pode escrever uma consulta e obter instâncias de objetos do tipo
correto com base nos dados da tabela OrderDetail. Naturalmente, você não
SUHFLVDDSHQDVGHFRQVXOWDVSROLPyU¿FDVYRFrSUHFLVDGHLQVHUo}HVDWXDOL]Do}HVHH[FOXV}HVSROLPyU¿FDVWDPEpP'HIDWRRFyGLJRTXHLQWHUDJHFRPD
base de dados tem tanto de recuperar quanto de atualizar dados, de forma que
você precisa resolver ambos os lados da incompatibilidade.
Figura 1.8 - Shirt e Shoes herda de Product, que é referenciada por OrderDetail.
A última diferença de que falaremos é de identidade. Bases de dados e
objetos têm diferentes conceitos de igualdade. As bases de dados baseiam a
identidade na coluna de chave primária, ao passo que objetos usam uma comparação de ponteiros.
1.4.5 A incompatibilidade de identidade
A incompatibilidade de identidade refere-se às diferentes formas pelas
quais objetos e bases de dados determinam a igualdade.
A identidade de uma linha, numa tabela, é representada pelo valor de suas
colunas de chave primária. Como resultado, você tem de prestar atenção ao
30 - Entity Framework 4 - A Estrutura de Entidades - em Ação
escolher uma chave primária para uma tabela. Às vezes, você pode querer usar
uma chave natural, tal como o código de um produto, mas esta opção pode
DSUHVHQWDUSUREOHPDVHPYH]GHVLPSOL¿FDUDVFRLVDV
Por exemplo, suponha que você precise mudar o código de um produto,
porque você inseriu um incorreto. O código do produto é uma coluna de chave
externa na tabela OrderDetail, então você tem de atualizá-la, também. O problema é que você não pode atualizar a coluna do código do produto na tabela
OrderDetail, porque se mudá-lo para um valor que ainda não exista na tabela
Product, você receberá um erro. Por outro lado, você não pode alterar o valor
na tabela Product, porque isso violaria a restrição de chave externa. Muitos
passos são necessários para se resolver este problema; o que parece ser uma
simples atualização acaba sendo um pesadelo.
Esse é provavelmente o problema mais incômodo, mas há outra razão
para se evitar o uso de chaves naturais. O código de um produto pode ser uma
string relativamente longa, e quase todas as bases de dados são otimizadas para
armazenar e pesquisar valores inteiros, de forma que a chave primária mais
H¿FLHQWHpXPDchave substituta, que é um valor sem sentido para o negócio.
Pelo uso de uma chave substituta, você deixa a carga de criá-la para a base de
dados, e pode se concentrar nos dados. O uso de chaves substitutas permite
que você altere dados em qualquer coluna da tabela, sem afetar nenhuma outra
tabela; você não tem de realizar uma complicada série de passos para alterar
o código do produto.
NOTA - Nós optamos por uma chave inteira, mas chaves GUID
também são boas. Em muitos cenários, GUIDs são uma opção
melhor que inteiros. Não há regra absoluta a este respeito; deve-se considerar caso a caso.
$WpDTXLSRGHPRVD¿UPDUTXHXPREMHWRpDUHSUHVHQWDomRRULHQWDGDSRU
objetos de uma linha da tabela, e que a propriedade de chave primária é o que
liga o objeto à linha. O problema é que, se você comparar dois objetos diferentes do mesmo tipo, eles acabam por ser diferentes, mesmo que contenham
os mesmos dados.
Por que objetos com os mesmos dados são diferentes? Porque, por omissão, duas variáveis que apontem para objetos diferentes que representem a
mesma linha de uma tabela são diferentes. Se as duas variáveis apontam para
a mesma instância, então eles são iguais. Isso é chamado de igualdade por
referência.
Uma abordagem que mude esse comportamento omissivo certamente
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 31
é mais desejável. Se dois objetos diferentes contêm os mesmos dados, sua
comparação deve retornar verdadeiro. No .NET, tal igualdade pode ser obtida
pela sobreposição dos métodos Equals e GetHashCode, indicando-se as
regras de igualdade nestes métodos. A maneira mais natural de representar
a igualdade é comparar propriedades que representem a chave primária na
tabela, mas há casos complexos em que esta abordagem não pode ser seguida.
1.4.6 Tratando as incompatibilidades
Agora que você viu todas as diferenças entre os mundos relacional e de
objetos, você terá uma ideia do que envolve a escrita de código que acessa a
base de dados em aplicativos baseados no modelo de objeto. Nós não falamos das técnicas para tratamento das incompatibilidades, mas você pode
IDFLOPHQWHDGLYLQKDUTXHXPVLVWHPDÀH[tYHOUHTXHUPXLWDVOLQKDVGHFyGLJR
Naturalmente, se você se concentrar na resolução dos problemas para um aplicativo individual, a solução será mais simples; mas se você quiser criar algo
reutilizável, a complexidade aumentará.
Em nossa experiência, uma das funcionalidades mais difíceis de implePHQWDU VmR DV FRQVXOWDV SROLPyU¿FDV 9RFr SUHFLVD DFRPRGDU R GHVLJQ GD
base de dados para criar consultas SQL ad hoc (por vezes muito complexas) e
escrever uma enorme quantidade de código para transformar corretamente em
objetos os dados extraídos pela consulta.
2VUHODFLRQDPHQWRWDPEpPWrPXPFXVWR&RPRD¿UPDGRDQWHVpIiFLO
escrever código que recupera os pedidos. Se você precisar recuperar pedidos
e detalhes, isso exige um pouco mais de trabalho, mas nada muito difícil. Seja
qual for o caminho que escolhido, você terá de escrever muito código para
tratar as funcionalidades de busca. Mesmo que esse código não seja muito
complicado de escrever, você ainda terá de escrevê-lo.
Felizmente, as incompatibilidades de tipo de dados e de granularidade são
triviais de se resolver. Tratar as diferenças de tipos de dados requer apenas
XPSRXFRGHGLVFLSOLQDSDUDYHUL¿FDUVHDVUHVWULo}HVGDEDVHGHGDGRVQmR
serão violadas quando os dados forem enviados de volta para atualização.
O problema da granularidade é ainda mais simples de tratar e não precisa de
atenção especial.
Às vezes, a forma como você modela as classes não pode ser representada numa base de dados, ou resulta num design pobre da base de dados.
Mesmo que as bases de dados e os modelos representem os mesmos dados, a
maneira como eles são organizados pode ser tão diferente que algum acordo
seja necessário.
32 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Em nossa experiência, criar um aplicativo para que ele funcione tão bem
quanto possa, muitas vezes envolve dobra e torção tanto da base de dados
quanto do modelo de objeto (principalmente do último) para que eles possam
parecer complicadamente postos. Alguém que olhe para eles poderia dizer
que o aplicativo não foi bem projetado. Estas são palavras frequentemente
ditas por puristas de um dos dois modelos, que consideram apenas o seu lado.
Lembre-se sempre: o melhor design é aquele que acomode ambos os modelo,
sem perder muito de seus benefícios.
Como você pode ver, um aplicativo que usa um modelo tem muitas complexidades, quando lidando com uma base de dados. A próxima pergunta é
quem tem de lidar com essa complexidade. A resposta é que, se você estiver
louco, poderá reinventar a roda por si próprio. Do contrário, poderá adotar
uma ferramenta de O/RM. Mais precisamente, você poderá usar a Estrutura
de Entidades.
1.5 Deixando que a Estrutura de Entidades facilite
sua vida
A chave para a entrega de um aplicativo que seja de fácil manutenção e
evolução é separar as questões em diferentes camadas lógicas e, às vezes, em
diferentes camadas físicas (tiers). Você pode obter muitos benefícios da adoção de tal técnica.
Antes de mais nada, há a separação de questões. Cada camada tem as suas
próprias responsabilidades: a camada de interface é responsável pela GUI;
a camada funcional mantém as regras funcionais e coordena a comunicação
entre a GUI e a camada de dados; e a camada de dados é responsável pela
interação com a base de dados.
'HSRLVTXHDLQWHUIDFHHQWUHDVFDPDGDVHVWLYHUGH¿QLGDHODVSRGHPHYRluir independentemente, permitindo o desenvolvimento em paralelo, que sempre acelera as coisas.
Outra grande vantagem do uso de diferentes camadas lógicas é a facilidade de manutenção e distribuição do aplicativo. Se precisar mudar a forma
GHDFHVVDUDEDVHGHGDGRVYRFrVyWHUiGHPRGL¿FDUDFDPDGDGHGDGRV$R
GLVWULEXLURVQRYRVSDFRWHVYRFrVyGLVWULEXLUiDVPRQWDJHQVPRGL¿FDGDGHLxando as outras intactas.
Obviamente, a camada de dados é a que é afetada pela adoção de uma
ferramenta de O/RM. Num aplicativo bem projetado, a GUI e a camada funcional não precisam saber que uma ferramenta de O/RM está em uso. Ela é
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 33
completamente imersa no código da camada de dados.
Vamos seguir em frente e examinar o que uma ferramenta de O/RM pode
fazer por nós.
1.5.1 O que é O/RM?
O/RM p XP DFU{QLPR HP LQJOrV TXH VLJQL¿FD mapeamento objeto/relacional. Em suma, uma estrutura de O/RM é usada para persistir objetos do
modelo numa base de dados relacional e para recuperá-los. Ela usa informações de metadados para interfacear com a base de dados. Desta forma, o
código de sua camada de dados não sabe nada sobre a estrutura da base de
dados; a ferramenta de O/RM se torna o meio de campo que oculta completamente a complexidade.
O coração do O/RM é o mapeamento – a técnica de mapeamento é o que
liga os mundos de objetos e relacional. Pelo mapeamento, você expressa de
que forma uma classe e suas propriedades se relacionam a uma ou mais tabelas na base de dados. Esta informação é usada pelo mecanismo da ferramenta
de O/RM para criar dinamicamente o código SQL que recupera os dados e
os transforma em objetos. Da mesma forma, pelo rastreamento de mudanças nas propriedades dos objetos, ele pode usar o mapeamento de dados para
enviar atualizações de volta à base de dados. As informações de mapeamento
geralmente são expressas como um arquivo XML. Como alternativa, algumas
ferramentas de O/RM usam atributos nas classes e em suas propriedades para
manter os dados de mapeamento.
Uma ferramenta de O/RM é uma complexa peça de software que poupa
o desenvolvedor do fardo de gerenciar a interação com a base de dados. Ele
trata da colisão entre os mundos de objetos e relacional, transforma os dados
GHFRQVXOWDVHPREMHWRVDFRPSDQKDDVDWXDOL]Do}HVGRVREMHWRVSDUDUHÀHWLU
DVPXGDQoDVQDEDVHGHGDGRVHPXLWRPDLV$LGHLDGHFRGL¿FDUHVVDVIXQcionalidades manualmente é absurda, quando você tem uma ferramenta que
faz isso por você.
Há muitas ferramentas de O/RM no mercado, tanto gratuitas quanto
comerciais. Até aqui, o NHibernate tem sido a mais poderosa e estável. A
estabilidade foi herdada de seu pai (o NHibernate é a portada para o .NET do
Hibernate, que é uma ferramenta de O/RM escrita em Java, disponível desde
2001), e o fato de ser um projeto de código aberto tem incentivado a sua adoção. Agora, sua liderança está sendo ameaçada pela nova versão da Estrutura
de Entidades.
34 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Na próxima seção, examinaremos por que a Estrutura de Entidades é uma
alternativa válida.
1.5.2 Os benefícios do uso da Estrutura de Entidades
³3RUTXHHXGHYHULDDGRWDUXPDIHUUDPHQWDGH250HPDLVHVSHFL¿FDmente, a Estrutura de Entidades? Quais os benefícios que eu obtenho com seu
uso? É uma tecnologia estável? Por que eu deveria adicionar outra estrutura
complexa ao meu aplicativo? “
Estas são as perguntas mais comuns que as pessoas que se aproximam
desta tecnologia pela primeira vez nos dirigem. Se você leu todo o capítulo,
até agora, deverá estar convencido de que a tecnologia de O/RM vale a pena
ser experimentada (se você tiver um modelo em seu aplicativo). Para obter
respostas completas às questões anteriores, você terá de ler pelo menos as
duas primeiras partes deste livro. Mas, aqui estão algumas respostas rápidas,
caso você não possa esperar:
Ŷ
Produtividade - em nossa experiência, o código de persistência que
não se baseia numa ferramenta de O/RM pode tomar até 35 por
cento do código de todo o aplicativo. O uso de uma ferramenta de
O/RM pode reduzir esse percentual para 5 por cento, em alguns
casos extremos, e de 15 a 20 por cento, numa situação normal. A
API que introduz a Estrutura de Entidades torna a vida do desenvolvedor mais fácil do que nunca. Apesar de suas limitações, o
GHVLJQHU LQWHJUDGR DR9LVXDO 6WXGLR VLPSOL¿FD GUDPDWLFDPHQWH R
processo de mapeamento;
Ŷ
Manutenibilidade – quanto menos linhas de código que você tiver,
menos linhas de código terá de manter. Isto é particularmente
válido no longo prazo, quando a remodelação entra em cena e uma
base de código menor é mais fácil de inspecionar. Além disso, a
capacidade de uma ferramenta de O/RM de preencher a lacuna
entre os modelos de objeto e relacional abre cenários interessantes.
9RFrSRGHUHPRGHODUDHVWUXWXUDGDEDVHGHGDGRVRXDGH¿QLomRGR
modelo, sem afetar o código do aplicativo, e apenas mudar o mapeamento. Se você pensar no código necessário para tratar manualmente a persistência e remodelar uma base de dados ou classes,
você entenderá imediatamente que a manutenibilidade aumenta se
você adotar uma ferramenta de O/RM; e
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 35
Ŷ
Desempenho – este é um dos assuntos mais discutidos relacionados com O/RM. A complexidade do O/RM apresenta uma evidente
desaceleração no desempenho. Na maioria dos casos, porém, esta
é uma troca aceitável, porque a desaceleração é quase irrelevante.
Vimos apenas um caso extremo em que a redução no desempenho
foi insuportável.
As características precedentes são partilhadas por todas as ferramentas de
O/RM disponíveis. Agora, vamos examinar os benefícios que a Estrutura de
Entidades acrescenta à sua fase de desenvolvimento.
Ŷ
Ŷ
Ŷ
Ela é incluída na Estrutura .NET. A Microsoft suporta plenamente a
Estrutura de Entidades e garante correções de erros, documentação
e melhorias num ritmo que seus concorrentes não conseguem acompanhar. Frequentemente, os clientes optam pela Estrutura de Entidades, em vez do NHibernate, porque a presença da Estrutura de Entidades na Estrutura .NET os tranquiliza a respeito da qualidade geral do
projeto. Além do mais, como a Estrutura .NET é gratuita, a Estrutura de Entidades também o é;
Ela é integrada no Visual Studio. Quando instala o Visual Studio
2010, você tem assistentes e um designer para controlar visualmente a fase de mapeamento, sem se preocupar com os detalhes de
implementação. Como você verá pelo resto do livro, o Visual Studio permite que você faça a engenharia reversa de bases de dados
existentes para criar automaticamente classes de modelo de objetos e arquivos de mapeamento e mantê-los atualizados quando o
design da base de dados mudar. Ela permite até mesmo o processo
inverso: a criação do modelo de objeto e, depois, a criação da base
de dados para persisti-lo. Caso faça qualquer alteração no modelo
de objeto, você poderá imediatamente recriar a base de dados;
A versão atual resolve a maioria dos problemas do passado. A
Microsoft ouviu atentamente o retorno da comunidade. Desde
a liberação da Estrutura de Entidades v1.0, a Microsoft engajou
um grupo de especialistas, incluindo Jimmy Nilsson, Eric Evans,
Martin Fowler e outros, para tornar a Estrutura de Entidades uma
grande concorrente. A primeira liberação da Estrutura de Entidades
IRL DWLQJLGR SRU XP YRWR GH GHVFRQ¿DQoD QD ZHE PDV D YHUVmR
atual resolve todos os problemas surgidos na época.
36 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Ŷ
Ŷ
Ŷ
Ŷ
Ŷ
Embora seu número de versão seja 4.0, esta é a segunda versão
da Estrutura de Entidades. No passado, a Microsoft confundia os
desenvolvedores com números de versão. A companhia forneceu a
Estrutura .NET 3.0, que não era uma nova versão, mas uma série
de classes, incluindo WCF, WPF e WF; mas a CLR ainda estava
na versão 2.0. Quando a Estrutura .NET 3.5 saiu, a CLR estava
novamente na versão 2.0. Montagens antigas permaneceram na
versão 2.0, enquanto que aquelas fornecidas na versão 3.0 e as
novas foram atualizadas para a versão 3.5. Esta política de versões
apresentou tanta confusão que com a Estrutura .NET 4.0, a Microsoft realinhou tudo para a versão 4.0. É por isso que temos a Estrutura de Entidades 4.0, em vez de 2.0;
Ela é independente do tipo de base de dados que você usa. A
camada de persistência usa a API da Estrutura de Entidades para
interagir com a base de dados. A Estrutura de Entidades é responsável pela tradução de chamadas a métodos em sentenças SQL que
são entendidas pela base de dados. Mas, mesmo que todas as bases
de dados modernas suportem o SQL padrão, muitas das funcionalidades diferem entre os fornecedores. Às vezes, há diferenças
sutis, mesmo entre versões diferentes do mesmo produto. O SQL
Server 2005 introduziu um grande número de melhorias, e uma boa
ferramenta de O/RM tem de gerar SQL otimizado tanto para a plataforma SQL Server 2005/2008 quanto para a SQL Server 7/2000.
A Estrutura de Entidades garante que o código SQL correto será
TXDVHVHPSUHJHUDGRHOLEHUDRGHVHQYROYHGRUGDYHUL¿FDomRGH
qual base de dados está em uso a cada comando.
,VVR DMXGD PXLWR PDV QmR VLJQL¿FD TXH YRFr SRGH HVTXHFHU GR
FyGLJR64/±YRFrVHPSUHWHUiGHYHUL¿FDURFyGLJR64/SURGXzido pela Estrutura de Entidades para ter certeza de que ele respeita
seus pré-requisitos de desempenho;
Ela usa o LINQ como linguagem de consulta. Você pode expressar
suas consultas usando o LINQ, e a Estrutura de Entidades cuidará
GHWUDGX]LUVXDFRQVXOWD/,14HPFyGLJR64/,VWRVLJQL¿FDTXH
YRFrSRGHHVFUHYHUFRQVXOWDVFRPR,QWHOOL6HQVHWLSL¿FDomRIRUWH
HYHUL¿FDomRQDFRPSLODomR1RPRPHQWRQHQKXPDRXWUDIHUUDmenta de O/RM no mercado (além do fantasma do projeto LINQ
para SQL) permite isso; e
A Estrutura de Entidades é recomendada para acesso a dados pela
Microsoft.$0LFURVRIWD¿UPDFODUDPHQWHTXHRIXWXURGRDFHVVR
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 37
a dados para a plataforma .NET é a Estrutura de Entidades. É por
isso que a empresa está trabalhando tão duro para tornar a Estrutura
de Entidades tão poderosa. A Microsoft também está trabalhando
em outros produtos para fazê-los depender da Estrutura de Entidades para acessar a base de dados.
Uma ferramenta de O/RM é útil, mas não vai salvar sua vida. Há muitos casos
em que seu uso não é viável. Na próxima seção, aprofundaremos este assunto.
1.5.3 Quando é que o O/RM não é necessário?
Nos últimos dois anos, o impulso em direção ao O/RM aumentou dramaticamente. Agora, muitos desenvolvedores acham que uma ferramenta de
O/RM é a solução bala de prata para todos os problemas, e tendem a usá-la em
todos os projetos. Às vezes, seu uso não é a escolha certa.
Apesar da enorme melhora na produtividade que ele oferece, o O/RM
é apenas uma estrutura. É algo que você tem que estudar e testar em várias
situações, e leva tempo para usá-lo corretamente. Em projetos com orçamento limitado, ou em que a data de entrega seja relativamente breve, tempo
pDOJRGHTXHYRFrQmRGLVS}HHYRFrWHPGHUHFRUUHUjFRGL¿FDomRPDQXDOGD
camada de acesso a dados.
O tipo de aplicação em desenvolvimento é outra coisa que você tem que
levar em conta ao optar por adotar ou não uma ferramenta de O/RM. Se estiver
desenvolvendo um aplicativo web que seja focado principalmente na exibição
de dados, uma ferramenta de O/RM pode ser um desperdício, porque você
extrai o melhor dela quando tem de recuperar e persistir objetos. Mesmo que
HODGrJUDQGHÀH[LELOLGDGHQDUHFXSHUDomRGHGDGRVYRFrSRGHQmRSUHFLVDU
dela se souber exatamente o qual é o nível de busca. Por exemplo, aplicativos
que geram relatórios estatísticos não terão nenhum benefício do O/RM. Eles
SURYDYHOPHQWHWDPEpPQmRVHEHQH¿FLDULDPGHXPPRGHOR
Se seu aplicativo dever executar inserções em massa, O/RM não é o que
você precisa. Bases de dados têm funcionalidades internas que permitem
inserções em massa, por isso é melhor se basear nessas funcionalidades.
Em suma, você deve sempre planejar com antecedência, antes de adotar
uma ferramenta de O/RM. Isto não é novidade; em nossa área, tudo deve ser
planejado antecipadamente.
38 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Até aqui, você viu que o trabalho com objetos melhora a estabilidade
do aplicativo e o torna mais fácil de manter. Aprendeu também que há uma
incompatibilidade entre os dados organizados em objetos e dados organizados
em bases de dados relacionais, e que esta incompatibilidade pode ser facilmente tratada por ferramentas de O/RM, como a Estrutura de Entidades. Na
próxima seção, examinaremos os componentes que compõem a Estrutura de
Entidades, e como esses componentes interagem entre si para resolver problemas de acesso a dados.
1.6 Como Estrutura de Entidades realiza o acesso
a dados
A Estrutura de Entidades é uma complexa peça de software. Sua arquitetura geral consiste de vários componentes, cada um cumprindo uma tarefa
HVSHFt¿FD$¿JXUDLOXVWUDRVSULQFLSDLVFRPSRQHQWHVGD(VWUXWXUDGH(QWLdades e dá uma ideia de onde cada um se encaixa.
EDM
LINQ to Enes
Enty SQL
Conceptual
model
Object Services
Mapping
Enty Client data provider
Storage
model
ADO.NET data provider
Database
cam na superior dos Serviços de Objetos, que dependem do Cliente de Entidade para interagir com a base de dados. O Cliente de Entidade usa os provedores ADO.NET padrões
!renciada por todas as outras e é usada por elas para obter metadados sobre as classes.
O Modelo de Dados da Entidade (EDM, na sigla em inglês) é a camada
em que o mapeamento entre as classes e a base de dados é expresso. Este
FRPSRQHQWHFRQVLVWHGHWUrVDUTXLYRVGHPDSHDPHQWRPRVWUDGRQD¿JXUD
O LINQ para Entidades e o SQL da Entidade são as linguagens usadas
para escrita de consultas ao modelo de objeto. O SQL da Entidade foi a primeira linguagem a ser desenvolvida, porque quando a Estrutura de Entidades
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 39
surgiu, o LINQ ainda estava em fase de protótipo e uma linguagem dedicada
para consultas era necessária. Durante o desenvolvimento, o LINQ atingiu a
estabilidade, então a equipe decidiu incluir um dialeto LINQ para a Estrutura
de Entidades. É por isso que, agora, temos duas linguagens de consulta na
Estrutura de Entidades.
A camada Serviços de Objetos é a porta para acesso a dados da base de
dados e para enviá-los de volta. Como resultado, este componente é o mais
importante para os desenvolvedores. Serviços de Objetos são responsáveis pela
materialização – o processo de transformação em objetos dos dados obtidos
do provedor de dados do Cliente da Entidade, que têm uma estrutura tabular.
Outra parte importante desta camada é o objeto ObjectStateManager ou
gerenciador de estado, que rastreia quaisquer alterações feitas nos objetos.
O provedor de dados do Cliente da Entidade, a que nos referiremos como
Cliente de Entidade, a partir de agora, é responsável pela comunicação com
os provedores de dados ADO.NET, que por sua vez se comunicam com a base
de dados. A principal tarefa desta camada é a converter as consultas SQL da
Entidade e LINQ para Entidades em sentenças SQL que sejam entendidas pela
base de dados subjacente. Além disso, eles convertem os resultados de consultas da estrutura tabular da base de dados numa estrutura tabular do modelo,
que é então passada aos Serviços de Objetos.
Agora que você tem uma ideia geral do que as partes do software fazem,
vamos discuti-las em maiores detalhes, começando com o EDM.
1.6.1 O Modelo de Dados da Entidade
O EDM é a ligação entre o modelo e a base de dados. Aqui, você descreve
as estruturas da base de dados e do modelo e como mapeá-las. O grande lance
do EDM é que ele desacopla seu aplicativo do armazenamento subjacente.
Base de dados e modelo podem ter estruturas completamente diferentes, mas
são sempre relacionados pelo EDM.
O EDM consiste de três arquivos XML, cada um com uma tarefa especí¿FD(VVHVDUTXLYRVHVWmRUHVXPLGRVQDWDEHOD
Em tempo de execução, esses arquivos são processados e seus dados são
armazenados em classes que pode ser consultadas para obtenção de metadados sobre as classes, sobre a base de dados, e sobre seu mapeamento. O principal aplicativo que usa os dados dessas classes é a própria Estrutura de Entidades. Quando ela materializa objetos a partir de uma consulta, ela solicita os
metadados ao EDM. Discutiremos o mapeamento em detalhes no capítulo 12.
40 - Entity Framework 4 - A Estrutura de Entidades - em Ação
+K[*'0(
Nome do arquivo
Descrição
Nome alternativo
Extensão
Modelo conceitual Descreve as
classes do
modelo e seus
relacionamentos
Esquema conceitual,
lado conceitual
CSDL
Modelo de
armazenamento
Descreve as
tabelas, vistas e
procedimentos
armazenados da
base de dados,
e suas chaves e
relacionamentos
Esquema de
armazenamento, lado
de armazenamento
SSDL
Modelo de
mapeamento
Mapeia os
modelos
conceitual e de
armazenamento
Esquema de
mapeamento, lado
de mapeamento
MSL
NOTA - Uma das funcionalidades mais desprezadas da Estru-
tura de Entidades é a extrema verbosidade do EDM. A criação
das classes e sua descrição no modelo é uma duplicação inútil.
A mesma objeção é feita contra o modelo de armazenamento,
porque o mecanismo pode analisar a estrutura da base de dados
H UHFXSHUDU R HVTXHPD SRU VL PHVPR 6H HOH R ¿]HVVH D ~QLFD
tarefa que o usuário precisaria fazer seria criar o arquivo de
mapeamento, como é o caso em outras estruturas. Existem várias
razões pelas quais a equipe incluiu todos os arquivos no EDM;
as principais são pelo desempenho e o máximo desacoplamento
das estruturas físicas.
O MODELO CONCEITUAL
O modelo conceitual é onde você descreve as classes do modelo. Este
arquivo é dividido em duas seções principais: a primeira é um contentor
que lista todas as entidades e os relacionamentos que são gerenciados pela
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 41
Estrutura de Entidades, e a segunda contém uma descrição detalhada de sua
estrutura.
Uma importante peculiaridade deste arquivo é que ele pode ser separado
HPYiULRVDUTXLYRV,VVRSRGHVHWRUQDU~WLOTXDQGRVHXPRGHOR¿FDUPXLWR
grande e o desempenho do designer do Visual Studio se tornar inaceitável.
Voltaremos a este assunto no capítulo 19, que é dedicado ao desempenho.
O MODELO DE ARMAZENAMENTO
O modelo de armazenamento é equivalente ao modelo conceitual, mas
descreve a organização da base de dados. Não só esse arquivo é conceitualmente similar ao anterior, mas também usa os mesmos nós XML. Ao contrário
do modelo conceitual, não é possível dividir este modelo em vários arquivos
físicos.
A primeira seção deste arquivo lista todas as tabelas, vistas, procedimentos
armazenados e chaves externas que são afetados. A segunda seção descreve os
itens listados no primeiro nó. Com relação a tabelas e vistas, as colunas e chaves primárias são descritas. Quando se trata de procedimentos armazenados,
parâmetros de entrada e saída são descritos. A descrição de uma chave externa
contém informações sobre a tabela envolvida, a cardinalidade, e as regras de
deleção e atualização.
O MODELO DE MAPEAMENTO
O arquivo de mapeamento é completamente diferente. Sua função não
é descrever algo, mas compensar as diferenças que existem entre os dois
modelos anteriores. É aí que a verdadeira mágica do mapeamento acontece:
você mapeia uma classe para uma ou múltiplas tabelas, mapeia uma tabela
SDUD XPD RX P~OWLSODV FODVVHV GH¿QH R PDSHDPHQWR GH KHUDQoD H PDSHLD
procedimentos armazenados tanto para atualizações quanto para recuperação
de objetos.
Há apenas um nó importante neste arquivo: ele associa a classe a uma
tabela e pode ser repetido mais de uma vez para assegurar que uma classe
possa ser mapeada para várias tabelas, e vice-versa.
Tal como o arquivo de descrição de armazenamento e diferentemente do
arquivo conceitual, o arquivo de mapeamento não pode ser dividido em múltiplos arquivos.
O ARQUIVO DE MAPEAMENTO DO VISUAL STUDIO
Como você verá na próxima seção, o Visual Studio tem um assistente que
gera automaticamente a informação de mapeamento a partir da base de dados,
HXPGHVLJQHUTXHSHUPLWHTXHYRFrPRGL¿TXHYLVXDOPHQWHRVPDSHDPHQWRV
sem se preocupar com os arquivos subjacentes.
Para se integrar facilmente os requisitos de mapeamento e o designer no
42 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Visual Studio, há um novo arquivo com a extensão EDMX. O arquivo EDMX
combina os três arquivos EDM em um, acrescentando informações exigidas pelo designer. A equipe de projeto da Estrutura de Entidades inventou o
DUTXLYR('0;SDUDSHUPLWLUTXHPRGL¿FDo}HVYLVXDLVIRVVHPIHLWDVQDVFODVses do modelo de objeto e seus mapeamentos para a base de dados, enquanto
que o EDM é a camada de mapeamento real. Em tempo de compilação, o
arquivo EDMX é dividido, e os três arquivos de mapeamento são gerados.
Em termos da incompatibilidade objeto/relacional, a camada de mapeamento é onde todos os problemas enumerados na secção 1.4 são resolvidos.
Mas o mapeamento apenas fornece metadados para resolver o problema – o
código se baseia nas camadas de Serviços de Objetos e de Cliente de Entidade. Na próxima seção, discutiremos a primeira.
1.6.2 Serviços de Objetos
Serviços de Objetos são a camada responsável por gerenciar objetos na
Estrutura de Entidades. A Estrutura de Entidades está mais interessada em
tratar a incompatibilidade entre a base de dados e os objetos, de forma que há
muitas tarefas a serem realizadas com os objetos.
A primeira funcionalidade chave dos Serviços de Objetos é que ele expõe
o API para gerar os objetos para os quais as consultas são escritas. Felizmente,
o assistente do Visual Studio ajuda muito na geração do código necessário
para a escrita de consultas, de modo que você só tem de se preocupar com a
consulta, não sobre as conexões.
Quando uma consulta é executada, a camada de Serviços de Objetos a traduz numa árvore de comandos que depois é repassada ao Cliente de Entidade
subjacente. O processo é um pouco diferente dependendo de qual tecnologia
de consulta que você use. Se você usar o LINQ para Entidades, o provedor
LINQ gerará uma árvore de expressões que é, então, processada e transformada na árvore de comandos. Se a consulta foi desenvolvida usando o SQL da
Entidade, os Serviços de Objetos processam a string e geram uma outra árvore
de comandos. Este processo é conhecido como transformação de consulta.
Figura 1.10 - Como os dados são recebidos pela camada de Serviços de Objetos
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 43
Quando a consulta na base de dados tiver sido executada e a camada subjacente tiver reorganizado os dados usando o mapeamento, os Serviços de
Objetos serão responsáveis pela criação dos objetos usando a estrutura de
entrada. Os dados de entrada são organizados em linhas e colunas, mas na
PDQHLUDGRPRGHORFRQFHLWXDOQmRQDIRUPDGDEDVHGHGDGRV,VWRVLJQL¿FD
que cada linha representa um objeto, e se ele tiver uma propriedade que refeUHQFLDRXWUDFODVVHDFROXQDFRQWHUiDOLQKDJHUDOGHVVDFODVVH$¿JXUD
ilustra como os dados são organizados.
Devido a esta organização de dados, o processo de criação de objetos é
bastante simples. Este processo é a materialização de objetos.
Quando os objetos estão prontos para ser consumidos, o contexto entra em
cena. Por contexto nós queremos dizer a vida útil da comunicação entre o aplicativo e a Estrutura de Entidades. Ela é estabelecida usando uma classe bem
conhecida (ObjectContext, ou contexto), e está ativa desde que a classe
seja referenciada no código ou que não seja descartada. A classe de contexto é
usada desde o início, porque esta classe cria o ponto de entrada para consultas
ao modelo de objeto.
Depois que os objetos são materializados, eles são automaticamente adicionados à memória do contexto, mas esse comportamento pode ser sobreposto por questões de desempenho. Durante o processo de materialização, se
o objeto que vai ser criado já existir na memória do contexto, ele será pulado
pelo mecanismo, e uma referência ao objeto na memória será retornada ao
FyGLJRTXHH[HFXWDDFRQVXOWD,VVRVLJQL¿FDTXHRFRQWH[WRDWXDFRPRXPD
espécie de cache local.
Os objetos que são anexados ao contexto são automaticamente rastreados
pelo componente gerenciador de estado. Este mecanismo assegura que todas
TXDLVTXHUPRGL¿FDo}HVIHLWDVDRVREMHWRVVHMDPFRUUHWDPHQWHJHUHQFLDGDVH
gravadas na base de dados. Para fazer isso, o gerenciador de estado armazena
os dados originais de cada objeto que é carregado, para que possa compará-los
e realizar uma atualização otimizada. Este componente oferece muitas opções
para personalização de seu comportamento.
3RU ¿P D FDPDGD GH 6HUYLoRV GH 2EMHWRV FRRUGHQD DV DWXDOL]Do}HV QR
armazenamento de dados, consultando o gerenciador de estado a respeito de
PRGL¿FDo}HVHFRQWURODDFULDomRGRFyGLJRGHFRQH[mRQHFHVViULRSDUDH[Hcutar os comandos.
Cada um dos passos precedentes será discutido em detalhes nos capítulos
4, 6, 7 e 8. Mas, agora que você sabe como os objetos são tratados, é hora de
investigar a camada que interage com a base de dados.
44 - Entity Framework 4 - A Estrutura de Entidades - em Ação
1.6.3 O provedor de dados do Cliente da Entidade
O Cliente da Entidade é o responsável pela comunicação com a base de
GDGRV 3DUD VLPSOL¿FDU VXD DUTXLWHWXUD HVWD FDPDGD QmR HVWi ¿VLFDPHQWH
conectada à base de dados, mas conta com a bem conhecida infraestrutura de
provedor de dados ADO.NET.
Enquanto os Serviços de Objetos gerenciam os objetos usando o modelo
conceitual do EDM, o Cliente de Entidade usa todos os arquivos EDM. Ele
precisa dos arquivos de modelo de mapeamento e de armazenamento para
converter a árvore de comandos em comandos SQL para execução na base de
dados. Depois, ele precisa do arquivo de modelo conceitual para converter os
resultados tabulares da base de dados em dados no formato conceitual, como
PRVWUDGRQD¿JXUDTXHVmRPDLVWDUGHSDVVDGRVSDUDREMHWRVSHORV6HUYLços de Objetos.
Neste ponto, você deve ter um claro entendimento de como o sistema trata
as consultas, usa-as para atingir a base de dados, e converte os dados resultantes em objetos. Em determinadas situações, onde o máximo desempenho é
exigido, você pode consultar essa camada diretamente, ignorando os Serviços
de Objetos. O grande impulso no desempenho é obtido não só pulando-se
uma camada na sequência, mas também evitando-se o processo de materialização, que é a tarefa mais lenta da execução da consulta. Por razões óbvias, o
LINQ para Entidades não pode ser usado quando você consulta diretamente
o Cliente de Entidade, porque o LINQ manipula objetos, e essa camada não
sabe nada sobre eles. O SQL da Entidade é a única linguagem que você pode
usar em tal cenário.
Agora, vamos passar à primeira opção de consulta: o LINQ para Entidades.
1.6.4 O LINQ para Entidades
2/,14SDUD(QWLGDGHVpRGLDOHWR/,14TXHSHUPLWHFRQVXOWDVWLSL¿FDdas ao modelo. Graças à sintaxe do LINQ, você pode escrever uma consulta
WLSL¿FDGDDRPRGHORHWHUXPREMHWRUHWRUQDGRFRPYHUL¿FDomRHPWHPSRGH
compilação.
Muito embora o LINQ para Entidades opere em objetos, ele ainda deve
VHUWUDGX]LGRSDUDR64/TXHVHUi¿QDOPHQWHHPLWLGRSDUDDEDVHGHGDGRV
Muitos dos métodos ou sobrecargas do LINQ não pode ser expressos em SQL.
Por exemplo, o método ElementAt não é suportado, mas ainda é sintaticamente válido. Uma chamada a este método não causará um erro em tempo de
Capítulo 1 - O acesso a dados recarregado: a Estrutura de Entidades - 45
compilação, mas produzirá uma NotSupportedException em tempo de
execução. Da mesma forma, a sobrecarga do método Where que recebe um
inteiro como segundo parâmetro não pode ser traduzida para o SQL, então,
seu uso causa apenas uma exceção em tempo de execução. Além dos métodos
QmRVXSRUWDGRVYRFrHQFRQWUDUiRXWURVFDVRVHPTXHDYHUL¿FDomRHPWHPSR
GHFRPSLODomRQmRpVX¿FLHQWHPDVHOHVVmRPXLWRUDURVHHVWmREHPGRFXmentados na MSDN.
NOTA - É importante enfatizar que o LINQ para Entidades não é
a Estrutura de Entidades. Muitos desenvolvedores tendem a ver o
LINQ para Entidades como uma tecnologia oposta ao LINQ para
SQL, mas isso é um erro. O LINQ para SQL é uma ferramenta
de O/RM completamente funcional que acompanha a Estrutura
.NET 3.5, enquanto que o LINQ para Entidades é apenas uma
linguagem de consulta dentro da Estrutura de Entidades. O LINQ
para Entidades é a principal linguagem de consulta na Estrutura
de Entidades, mas o SQL de Entidade ainda é uma ótima ferramenta para você ter em sua caixa de ferramentas.
1.6.5 O SQL da Entidade
O SQL de Entidade é a segunda maneira de consultar o modelo de objeto.
Como as consultas do LINQ para Entidades, as consultas do SQL de Entidade
são sempre expressas para o modelo. A diferença é que o SQL de Entidade é
baseado em strings, de modo que ele pode ser preferível em alguns cenários.
O SQL de Entidade é uma das linguagens mais complicadas que nós já
encontramos. Quando a equipe da Estrutura de Entidades teve de criar uma
linguagem de consulta para a Estrutura de Entidades (antes do LINQ estar
disponível), eles queriam criar uma linguagem que fosse fácil para os desenvolvedores entenderem e optaram por uma sintaxe no estilo do SQL (que é
por que ela foi chamada de SQL de Entidade). À medida que a Estrutura de
Entidades evoluiu, e mais e mais funcionalidades foram adicionadas, o espectro de capacidades de consulta se ampliou, e novas funções foram exigidas na
linguagem. Atualmente, ela inclui mais de 150 funções e manteve apenas uma
pequena compatibilidade com a sintaxe SQL original.
Embora seja complexo, o SQL de Entidade está à frente do LINQ para
Entidades, em algumas situações. Primeiro, ele é baseado em strings, portanto,
é mais fácil criar consultas em tempo de execução com base em condições.
46 - Entity Framework 4 - A Estrutura de Entidades - em Ação
Segundo, o SQL de Entidade é a única linguagem que pode ser usada para
recuperar dados em baixo nível, usando diretamente o Cliente de Entidade.
3RU ¿P Ki IXQo}HV TXH QmR SRGHP VHU LQYRFDGDV XVDQGRVH R /,14 SDUD
Entidades, mas podem sê-lo usando-se o SQL de Entidade. Você aprenderá
mais sobre isso no capítulo 9.
1.7 Resumo
Neste capítulo, você viu o que é O/RM, quais os problemas que ele resolve,
e como ele se encaixa no projeto de aplicativos.
Você aprendeu o básico do acesso a dados usando estruturas prontas para
uso, como datasets (conjuntos de dados) e leitores de dados, e por que eles
são usados em alguns ambientes e desencorajados em outros. Em cenários
onde estruturas tabulares não são aplicáveis, um modelo de objeto/domínio é
a substituição óbvia, porque o uso de classes permite que você tire proveito do
poder da programação orientada por objetos.
Naturalmente, a introdução de um modelo de domínio carrega consigo
uma nova série de problemas, devido a muitas diferenças que existem entre as
representações de dados de objeto e relacional. O tratamento de tais diferenças
às vezes é fácil para aplicativos de negócios de pequeno e médio porte, mas
pode resultar em código excessivo à medida que os aplicativos crescem.
É aí que as ferramentas de O/RM, como a Estrutura de Entidades, entram
em cena. Como você viu, as ferramentas de O/RM tornam mais fácil o desenvolvimento e a manutenção do código de interação com a base de dados.
Embora as ferramentas de O/RM não sejam a bala de prata para qualquer
DSOLFDWLYRXPDPSORHVSHFWURGHDSOLFDWLYRVSRGHVHEHQH¿FLDUGDDGRomRGR
O/RM.
3RU ¿P YRFr DSUHQGHX VREUH RV FRPSRQHQWHV FHQWUDLV GD (VWUXWXUD GH
Entidades e como eles interagem para resolver as incompatibilidades objeto/
relacional.
Você ainda não viu a Estrutura de Entidades em ação, mas, no próximo
capítulo, nós começaremos a lidar com sua complexidade e a aprender como
trabalhar com ela.
Download