Visual Basic em Português

Página pessoal de Jorge Paulino sobre o Visual Basic (VB.NET, ASP.NET, VB6, VBA) e algumas noticias de tecnologia

Introdução ao Entity Framework

O ADO.NET Entity Framework permite criar aplicações em que o acesso a dados é feito com base em um modelo conceitual e não utilizando comandos directos à base de dados. Isto permite que o programador se abstraia totalmente da base de dados (criação de ligações de acesso, comandos, parâmetros, etc.) e utilize apenas objectos durante o desenvolvimento.

A versão 4.0 do Entity Framework (actual), que está disponível na .NET Framework 4.0, tem um conjunto de novas funcionalidades e melhorias, como é o caso de suporte a POCO - Plain Old CLR Objects (permite criar classes que não herdam, nem implementam nenhuma outra classes ou interface), abordagem Model-First (permite criar primeiro o modelo conceptual e, com base nele, criar a base de dados), suporte para o uso de funções em LINQ-to-Entities, Complex Types (criação de tipos de dados complexos), Deferred Loading ou Lazy Loading (capacidade de carregar as propriedades de associação das entidades no momento em são chamadas, se forem chamadas), etc.

Não é especifica apenas para o SQL Server, pois existem providers que permitem usar outras bases de dados, como Oracle, MySql, PostgreSQL, DB2, SQL Anywhere, Ingres, Progress, Firebird, Synergy, etc.

Existem várias vantagens na utilização de um ORM (Object-relational mapping), que tornam a sua adopção quase inevitável, mas vejamos o seguinte exemplo:

“SELECT * FROM utilizadores WHERE nome = ‘Jorge’ AND morada = ‘Moita’”

Este exemplo irá listar todos os utilizadores que tenham como nome “Jorge” e que tenham como morada a “Moita”.

Imaginemos que o programador ou o DBA (database administrator) altera o campo “nome” para “nomecompleto”, pois quer que se registe o nome completo do utilizador e, desta forma, o nome do campo fica mais coerente. Se aplicação for compilada não é detectado qualquer problema e só no momento de execução irá ocorrer um erro. Situações como estas são muito frequentes e podem representam vários erros na aplicação.

Este é apenas um exemplo de como se pode beneficiar, e muito, da utilização do Entity Framework, mas existem muito mais vantagens como a utilização de LINQ to Entities, intellisense no momento em que se está a escrever o código, código mais fácil de manter e actualizar, etc, etc.

Neste artigo, que será uma breve introdução ao Entity Framework, irá apenas mostrar como construir um modelo relacional de uma base de dados SQL, uma abordagem database-first, e como executar algumas operações CRUD.

CRIAÇÃO DO MODELO RELACIONAL (database-first)

Para criação de um modelo relacional iremos usar a seguinte base de dados SQL:

Como é possível ver nesta imagem, existem apenas 3 tabelas, com as respectivas chaves primárias/estrangeiras: produtos, clientes e uma terceira tabela onde se registam os movimentos.

O primeiro passo é adicionar um novo item ao projecto (menu Project – Add New Item), e seleccionar no grupo de templates “Data” o item “ADO.NET Entity Data Model”. Isto irá iniciar um Wizard que permitirá criar o modelo final.

De seguida seleccionar “Generate from database” e carregar em “Next”. A próxima opção permite fazer a ligação à base de dados, escolhendo uma já existente ou criando uma nova ligação.

Para o nome da ligação, e para este exemplo, utilize “vendasEntities“.

A última opção deste Wizard é onde são seleccionados os objectos a utilizar no modelo. Neste exemplo são escolhidas as três tabelas já referidas.

Após este processo está criado o ficheiro EDMX, que não é mais do que um conjunto de classes e métodos que nos permitirá aceder à base de dados de uma forma simples, como iremos ver de seguida.

OPERAÇÕES CRUD

As operações CRUD (acrónimo de Create, Read, Update e Delete em Inglês) são quatro operações básicas e fundamentais para a manipulação de bases de dados. São por isso bastante importantes e requerem, sem a utilização de um ORM como o Entity Framework, algum trabalho que é normalmente complexo.

Com o Entity Framwork este trabalho está bastante simplificado para o programador, necessitando apenas de algumas linhas de código, com recurso a IntelliSense, para as executar.

O funcionamento para todas as operações é semelhante: é criada uma nova instância da nossa entidade (neste exemplo “vendasEntities”) que herda de uma classe da EntityFramework chamada ObjectContext, que a classe primária e responsável de gerir a informação como objectos e a ligação dos objectos aos dados.

Inserir registos

Para inserir novos registos, neste caso um novo cliente, criamos uma nova instância da respectiva classe, definindo as suas propriedades, que correspondem aos respectivos campos. Depois adicionamos o objecto através do método AddObject() e, finalmente, executamos o método SaveChanges() que irá efectuar as respectivas alterações, neste caso inserir um registo, na base de dados

        Using context As New vendasEntities

            ' Cria um novo cliente
            Dim cliente As New clientes With
                {
                    .nome = "Rui Paulo",
                    .morada = "Lisboa",
                    .datanascimento =
                        New DateTime(1980, 10, 31)
                }

            context.clientes.AddObject(cliente)
            context.SaveChanges()

            ' Podemos verificar logo o número (ID) do registo inserido
            Debug.WriteLine("Número de registo: " & cliente.id.ToString())

        End Using

Apagar registos

Para apagar um registo é necessário seleccionar o registo correcto, neste caso usando uma Lambda Expression, e caso o resultado seja válido, executamos o método DeleteObject(), indicando o registo a apagar. Finalmente gravamos as alterações na base de dados.

        Using context As New vendasEntities

            ' Procura o registo com o número de cliente (ID) igual a 1
            Dim cliente = context.clientes.Where(
                        Function(c) c.id = 1).FirstOrDefault()

            If cliente IsNot Nothing Then
                context.clientes.DeleteObject(cliente)
                context.SaveChanges()
            Else
                MessageBox.Show(
                    "Número de cliente inválido")
            End If

        End Using

Modificar Registos

Para modificar um registo, e à semelhança da operação anterior, é necessário seleccionar o registo. Neste exemplo utilizamos LINQ to Entities para fazer essa selecção. Depois, modificamos o que for para modificar e finalmente gravamos as alterações.

        Using context As New vendasEntities

            Dim cliente =
                (From c In context.clientes
                 Where c.id = 1
                 Select c).FirstOrDefault()

            If cliente IsNot Nothing Then
                With cliente
                    .nome = "Rui Paulo"
                    .morada = "Setúbal"
                    .datanascimento = New DateTime(1979, 10, 31)
                End With
                context.SaveChanges()
            Else
                MessageBox.Show(
                    "Número de cliente inválido")
            End If

        End Using

Listar Registos

A listagem de registo é também muito semelhante às operações anteriores. Neste exemplo, usando LINQ to Entities, vamos seleccionar todos os registo com base num critério, para uma variável do tipo IQueryable(Of T), e depois efectuamos um ciclo para mostrar os resultados obtidos.

        Using context As New vendasEntities

            Dim listaClientes =
                From c In context.clientes
                Where c.morada.Contains("Lisboa") And
                c.datanascimento <
                        New DateTime(1985, 1, 1)
                Select c

            For Each c As clientes In listaClientes
                Debug.WriteLine(c.nome)
            Next

        End Using

Entre entidades existir normalmente associações, e essas associações (também representadas na última imagem), têm algo que se designa por Navigation Properties. As Navigation Properties permitem uma navegação bidireccional entre entidades, de acordo com as suas associações. Isto é algo bastante prático pois permite-nos criar queries entre várias entidades usando LINQ to Entities.

O seguinte exemplo mostra esta abordagem, definindo depois o resultado como DataSource num controlo DataGridView.

        Using context As New vendasEntities

            Dim listaClientes =
                From c In context.clientes
                Join m In context.movimentos
                    On m.clienteid Equals c.id
                Join p In context.produtos
                    On m.produtoid Equals p.id
                Select m.datavenda,
                       c.nome,
                       p.produto,
                       m.preco

            Me.DataGridView1.DataSource = listaClientes

        End Using

NOTA: Se utilizar uma base de dados anexa ao projecto (AttachDb), a base de dados é copiada para as pastas Debug/Release. Pode seleccionar no menu Project a opção Show All Files e verificar as alterações nessa localização.

CONCLUSÃO

Como foi possível ver ao longo do artigo, que abordou de uma forma muito superficial algumas das funcionalidades deste ORM, o Entity Framework é uma excelente opção para se trabalhar com bases de dados.

É simples de utilizar, permite-nos trabalhar apenas com objectos e com intellisense, resolve inúmeros problemas que são habituais quando trabalhamos directamente com a base de dados (formatos de datas, números, caracteres especiais), etc.

Estas são apenas algumas, das muitas vantagens, que nos devem fazer de uma vez por todas, deixar de usar SqlCommands, SqlConnections, DataSets, etc.

Alguns recursos interessantes:

Data Developer Center
http://msdn.microsoft.com/en-us/data/ef.aspx

Data Access Hands-on Labs
http://msdn.microsoft.com/enus/data/gg427655.aspx

ADO.NET team blog
http://blogs.msdn.com/b/adonet/

Julie Lerman's Blog
http://thedatafarm.com/blog/

NOTA: Este artigo está também disponível na revista PROGRAMAREdição nº 26 de Dezembro 2010

6 comentários:

Anónimo disse...

E desvantagens? Existem situações que não deverá ser utilizado suponho...

Todas esta abstração deve ter implicações a nível de performance. Comporta-se bem com grandes volumes de dados?

Jorge Paulino disse...

Olá,

Existe obviamente um custo pela utilização de um ORM, mas na maioria dos casos é minimo.

Excepto em casos especificos onde a informação é realmente grande e tem de ser tratada com grande velocidade, o EF pode ser muito bem utilizado.

Mas é testar e ver os resultados especificos para cada caso.

Recomendo a leitura deste artigo, disponível na MSDN: Performance Considerations (Entity Framework)

Horus Ra Herakty disse...

Excelente artigo para as bases do entity... pena não ter sido em C# e não ter explorado as relações não por JOIN mas por associações em tabelas de relação, que é a área que faz mais confusão no ppl pelas questões que vejo.
Mas os meus PARABÉNS tb pelo teu SPOT LIGHT na MSDN nacional :)

Em relação ao uso de um ORM... falo por mim e uso aquela expressão. "Depois de experimentar nunca mais quis outra coisa."

Para quem acompanha a programação desde o inicio, digo que é brutal trabalhar-se com uma BD em forma de entidades(objectos) e poder trabalhar com elas usando LINQ. E assim ficam mesmo tudo objectos(classes), totalmente OOP até na BD.

Também realço o que o Paulino disse a nível de actualizações, quer da BD, quer do modelo.
Com querys tinhas de andar em todo o lado a procurar o que alterar... agora é com um clique e na v4 é bidirecional. Podes criar um modelo a partir de uma BD, como podes criar uma BD a partir de um modelo.
São dois passos num só que poupa tempo e dores de cabeça.
Para quem trabalha diariamente nisto, com tempos apertados e tudo mais estas coisas ganham uma vantagem extraordinária (O tal RAD).
Agora é realmente rápido desenvolver e criar uma BD num diagrama é fabuloso. Podem criar o modelo sem BD e depois o modelo cria a BD. acho fixe.

E a v4 tá mt completa... poderia falar eternamente dela, como numa linha de código fazer uma lista de strong typed objects a partir de dados em BD, usando o ToList(tipoDoObjecto>()
NOTA: no exemplo em cima tive de mudar o sinal de menor, como é na verdadeira sintax do C#.

enfim... usem...

Parabéns ao Paulino e sinceramente aconselho a todos começarem a usar um ORM (pode ser outro), pois a programação torna-se mais rápida, fluida e usam as mesmas formas em tudo. a forma como já trabalhavam com as vossas classes, podem agora trabalhar tb com dados directamente da BD, sem que saibam sequer que existe uma BD :)

cumprs,
José Domingos (aka teckV)

Jorge Paulino disse...

Obrigado pelo comentário José Domingos ;)

Realmente é outro mundo trabalhar com um ORM (EF, NHibernate, etc) e facilita realmente muito.

Provavelmente em breve irei escrever mais artigos sobre Entity Framework 4.0 (model first, POCO, etc)


PS: Ainda cheguei a começar a preparar também em C#, mas como era para a revista PROGRAMAR para a secção de VB, acabei por não o fazer. Mas a conversão é bastante simples!

Anónimo disse...

Boa tarde,

Não sei se me pode ajudar, mas eu comecei a utilizar uma base em mysql, só agora o código que utilizava que era idêntico ao aqui exposto, não funciona, na tutalidade.

Por exemplo for each c in nop

Anónimo disse...

Já percebi o que se passa

Não atualiza a base.

Não sei é o que falta..

João Carvalho

Mensagens Recentes



Microsoft Office Especialist

Membro da Comunidade
Experts-Exchange


Administ. da Comunidade
Portugal-a-Programar



Twitter

Artigos no CodeProject

Artigos no CodeProject

Subscrever Novidades

Endereço de Email:

Delivered by FeedBurner

Seguidores

Histórico