Consegui ler a documentação sobre POCO no EF4 no MSDN e fazer meus primeiros testes. O que eu achei:

O suporte a POCO no EF4 é muito bom. Os caras criaram um ORM que permite modelar a entidade conceitual, que depois vai mapear para a classe em si. Depois você deve modelar o mapeamento dela com um banco de dados ou gerar um banco de dados novo, e criar sua própria classe para utilizar com o modelo conceitual. Ficou ótimo. Vou colocar aqui um exemplo simples.

No meu exemplo estou usando um projeto console simples. Não me interessam os padrões de projeto ou arquitetura, me interessa ver o EF4 funcionando. A primeira coisa é criar o arquivo do EF, o EDMX. Vou fazer aqui um início de um sistema de blogs, que é algo que todo mundo conhece.

Observação: Não existiu EF2 ou EF3. Existiu EF1 que é a que saiu com o SP1 do .Net Framework 3.5. Depois saiu o .Net Framework 4.0, e agora todo mundo fala em EF4, por causa do .Net Framework 4, não em EF2.

Primeiro crio o EDMX do zero (sem banco de dados) e crio duas entidades:

 EDMX do EF

Até aí nada de mais.

No solution explorer eu retiro o texto de "Custom Tool", vejam abaixo:

 Solution Explorer do EDMX

Isso é importante para que o arquivo .cs não seja gerado junto ao modelo. Deste jeito temos apenas um modelo conceitual e não as classes geradas (classes do contexto do EF, das entidades, etc).

Preciso criar então as classes. Nada de mais, as classes são simples. Classe de Post:

using System.Collections.Generic;
namespace BlogEF4
{
    public class Post
    {
        public virtual int Id { get; set; }
        public virtual string Body { get; set; }
        private IList<Comment> _comments = new List<Comment>();
        public virtual IList<Comment> Comments 
        {
            get { return _comments; }
            set { _comments = value; } 
        }
    }
}

A propriedade "Comments" não é automática porque eu quero inicializá-la. Se tornasse ela automática só poderia fazer isso no construtor, só que se houver uma classe proxy (mais sobre isso a frente), eu teria problemas. Tente fazer, e você também vai ter.

A classe de comentários é simples também:

namespace BlogEF4
{
    public class Comment
    {
        public virtual int Id { get; set; }
        public virtual string Text { get; set; }
        public virtual Post Post { get; set; }
    }
}

Super simples, certo? Notaram os "virtuals" lá? Isso está lá para permitir que o EF crie "classes proxy" no lugar das classes reais. Isso não é obrigatório, mas é a única maneira de ter lazy loading no EF, e de ganhar uma boa performance no acompanhamento de mundaças do EF. Se você não fizer isso, para acompanhar as mudanças o EF vai tirar uma cópia dos dados e guardar. Desta forma ele cria uma classe que herda da sua, e coloca lá todo o código necessário para fazer o acompanhamento de mudanças. Imagino que, na prática, esta nova classe implemente as interfaces do EF, criando efetivemante uma IPOCO, e essa então faz todo o trabalho de acompanhamento. Para saber o que você precisa fazer para usar uma classe proxy, veja a documentação do EF no MSDN (a documentação também é beta).

Com isso, eu tenho que criar um contexto do EF. O contexto normalmente é criado pela ferramenta, mas como eu desabilitei o gerador de código, ele não está mais sendo criado. Mas o código é simples:

using System.Data.Objects;
namespace BlogEF4
{
    class BlogContext : ObjectContext
    {
        public BlogContext()
            : base("name=BlogModelContainer", "BlogModelContainer")
        {
        }
        private IObjectSet<Post> _posts;
        public IObjectSet<Post> Posts 
        {
            get 
            {
                if (_posts == null)
                {
                    _posts = CreateObjectSet<Post>();
                }
                return _posts;
            }
        }
    }
}

Ele herda de ObjectContext, que pede no construtor a string de conexão (que criaremos em seguida), e o nome do container, que deve estar criado no contexto (arquivo EDMX – você acha esse nome clicando no espaço em branco do Canvas e visualizando suas propriedades). A propriedade Posts é um IObjectSet, que herda de IQueryable, ou seja, continuamos com suporte total ao LINQ.

Falta só criar o banco e o novo EF permite trabalhar "Model First", o que também é uma grande melhoria. Você vai precisar criar a database antes, então faça isso. Depois disso basta clicar com o botão direito sobre o canvas do designer do EF e selecionar "Generate Database Script From Model…". Isso vai abrir um wizard que vai ter permitir selecionar o banco, e no fim vai gerar um script salvo no diretório do projeto, que você vai poder rodar direto pelo Visual Studio.

Gerando a base a partir do modelo

Final do Wizard:

DDL gerado

Arquivo salvo, basta clicar no botão para rodar:

Arquivo SQL pronto para rodar

No final o arquivo EDMX vai ser atualizado com as informações do banco de dados, e o seu web.config/app.config vai ter a string de conexão adicionada:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings><add name="BlogModelContainer" connectionString="metadata=res://*/BlogModel.csdl|res://*/BlogModel.ssdl|res://*/BlogModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\sqlexpress;Initial Catalog=Blog;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" /></connectionStrings>
</configuration>

E é isso aí. Agora é só testar. Vejam minha classe de programa (console):

using System;
using System.Linq;
namespace BlogEF4
{
    class Program
    {
        static void Main(string[] args)
        {
            SaveEntities();
            ShowEntities();                        
            Console.ReadKey();
        }

        private static void SaveEntities()
        {
            var context = new BlogContext();
            context.ContextOptions.DeferredLoadingEnabled = true;
            var post = new Post { Body = "novo b" };
            post.Comments.Add(new Comment { Text = "novo c", Post = post });
            context.AddObject("PostSet", post);
            context.SaveChanges();
        }

        private static void ShowEntities()
        {
            var context = new BlogContext();
            context.ContextOptions.DeferredLoadingEnabled = true;
            var posts = context.Posts.ToList();
            foreach (var post in posts)
            {
                Console.WriteLine("Post id: {0} Body: {1}", post.Id, post.Body);
                foreach (var comment in post.Comments)
                {
                    Console.WriteLine("Comment id: {0} Comment Text: {1}", comment.Id, comment.Text);
                }
            }
        }
    }
}

Notem que estou fazendo consulta e inclusão, e tudo funciona. Vejam o resultado:

Resultado do programa

O SQL que está rodando também é bem simples. Como tem lazy loading, são os seguintes (sniffei eles com SQL Profiller):

--Incluido posts:
exec sp_executesql N'insert [dbo].[PostSet]([Body])
values (@0)
select [Id]
from [dbo].[PostSet]
where @@ROWCOUNT > 0 and [Id] = scope_identity()',N'@0 nvarchar(max) ',@0=N'novo b'

--Incluindo comments:
exec sp_executesql N'insert [dbo].[CommentSet]([Text], [Post_Id])
values (@0, @1)
select [Id]
from [dbo].[CommentSet]
where @@ROWCOUNT > 0 and [Id] = scope_identity()',N'@0 nvarchar(max) ,@1 int',@0=N'novo c',@1=5

--selecionando posts:
SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Body] AS [Body]
FROM [dbo].[PostSet] AS [Extent1]

--selecionando os comments de um post:
exec sp_executesql N'SELECT 
1 AS [C1], 
[Extent1].[Id] AS [Id], 
[Extent1].[Text] AS [Text], 
[Extent1].[Post_Id] AS [Post_Id]
FROM [dbo].[CommentSet] AS [Extent1]
WHERE [Extent1].[Post_Id] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

Sem segredos.

É bom notar que esse padrão de consulta que estou fazendo é errado. É o chamado SELECT N+1, onde vou fazer uma consulta a mais para cada post, para pegar os comentários. O ideal seria fazer isso sem lazy loading, já que vou ter N consultas para cada post, mais uma para obter os posts (por isso chama N+1).

Meus feelings sobre esse primeiro contato:

A Microsoft deu um GRANDE passo com essa nova versão. Só este suporte a POCOs já está muito legal. Vi também que há outras forma de trabalhar o carregamento dos dados, depois coloco aqui. O acompanhamento das mudanças dos dados também é feito de maneira interessante. Com T4 seremos capazes de gerar o código das classes, algo que ainda não vi. De qualquer forma, não gosto de código gerado, e já disse isso aqui antes, então não é algo que valorizarei de qualquer forma. Código gerado é bom só na interface gráfica, e ainda assim, com cuidado. Poder trabalhar model first, gerando o banco, também é bem legal. Seria legal ser capaz de gerar o banco programaticamente. Isso é especialmente útil em PoCs e protótipos, mas de qualquer forma é muito bom que agora podemos trabalhar o modelo antes.

A única coisa que não gostei é que, se quero ter lazy loading, sou obrigado a deixar todas as minhas propriedades públicas. Não consigo aplicar um padrão onde eu esconderia a coleção em uma propriedade protected ou private, e daria acesso a ela apenas como um IEnumerable, ou seja, ela não poderia ser alterada, permitindo alterações apenas através de métodos controlados, como um "AddComment". Eu só posso fazer isso se abrir mão de lazy loading, e isso geralmente não é uma opção. Isso é especialmente útil em cenários de relações bidirecionais. Veja um exemplo no MSDN onde a pessoa fez exatamente isso (sem lazy loading). Um maneira de lidar com isso seria trabalhar com repositórios checando as relações, mas isso é ruim. Ou ainda trabalhar com interfaces para as entidades, mas isso geralmente implica em um overhead de manutenção (apesar de também facilitar testes). Preciso analizar o conjunto melhor com relação a isso.

O que vocês acharam?


Postado na(s) categoria(s) Mapeadores O/R pelo giovanni bassi em 25 de maio de 2009 às 03:08 | Tags:

Comentários


maio 25. 2009 05:40
Rodrigo Vieira
Acho que a Microsoft tá de parabéns, por ter ouvido o feedback da comunidade. Procuraram cobrir cada ponto criticado no EF1.

Agora o NHibernate vai ter competição de verdade, e a gente ganha com isso.

http://blog.rodbv.com/http://blog.rodbv.com/


maio 25. 2009 09:29
Juliano Oliveira
Interessante!

Espero que melhorem ainda mais até o lançamento.

[]´s

http://programandoem.net/http://programandoem.net/


maio 25. 2009 23:06
Zote
Interessante...

Vou fazer uns testes, e numa dessas criar uma versão paralela daquele projeto que você nos ajudou a iniciar...

Abraço

http://gofrom.us/http://gofrom.us/


Brazil Rafael Silva Oliveira
junho 25. 2009 23:13
Rafael Silva Oliveira
Acabei de ler este post e achei interessante.
Uma dúvida que me veio é: posso começar a desenvolver aplicações comerciais com o EF4? Não terei dor de cabeça até sair a versão final no ano que vem?

Abraço a todos

no site


junho 26. 2009 00:18
Giovanni Bassi
Oi Rafael,
A versão que temos em mãos agora é considerada "feature complete", ou seja, possui todas as funcionalidades esperadas na versão final.
Em resumo: você não deve ter dor de cabeça quando a versão final sair.

http://unplugged.giggio.net/http://unplugged.giggio.net/


 Denis Petri
julho 16. 2009 15:52
Denis Petri
Oi Giovanni Bassi, você pensa em criar video aula (ou qualquer outro meio) com um sistema simples em camadas usando o EF no Visual Studio 2010? Seria bem interessante!!!! Alias parabéns por este post, me ajudou muito com o EF. Obrigado!!!!

no site


julho 16. 2009 17:44
Giovanni Bassi
Por enquanto não... sigo falando sobre ele...

http://unplugged.giggio.net/http://unplugged.giggio.net/


Brazil Rodrigo
julho 23. 2009 23:04
Rodrigo
Parabéns, muito bom o Post!

Gostaria de saber se o EF4 também suporta propriedades derivadas e se é possível fazer consultas com o Linq através dessas propriedades!

no site


agosto 27. 2009 00:47
pingback
Pingback from unplugged.giggio.net

Tech Ed Brasil 2009: Segundo dia

http://unplugged.giggio.net/unplugged/post/Tech-Ed-Brasil-2009-Segundo-dia.aspxhttp://unplugged.giggio.net/unplugged/post/Tech-Ed-Brasil-2009-Segundo-dia.aspx

Comentar


(Vai mostrar seu Gravatar)

  Country flag

biuquote
  • Comentário
  • Pré-visualização
Loading



Quem é Giovanni Bassi

Giovanni Bassi Sou uma pessoa apaixonada por tecnologia e especificamente por .Net. Sou consultor independente especialista em .Net, focado em arquitetura e melhores práticas. Tenho dezenas de artigos publicados na .Net Magazine, revista da qual sou editor técnico. Ministro palestras e cursos de vez em quando, e quando dá tempo eu respiro um pouco. Mais detalhes nesta página.

Busca

Selos

MVP

MCPD

MCSD

.Net Magazine

Abaixo ao if!

Calendário

«  fevereiro 2010  »
seteququsedo
25262728293031
1234567
891011121314
15161718192021
22232425262728
1234567
Ver detalhamento de posts no calendário

Blogs interessantes

    OPMLDownload OPML file

    Postagens recentes

    Comentários recentes

    Disclaimer / Aviso
    As opiniões colocadas neste blog são minhas e pessoais e não expressam necessariamente as opiniões de meus empregadores, pareceiros e amigos. Da mesma forma, os comentários feitos por leitores do blog não expressam a minha opinião.

    © Copyright 2010 .Net Unplugged
    Log in