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

Mostrar mensagens com a etiqueta Visual Studio 2010. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Visual Studio 2010. Mostrar todas as mensagens

Entity Framework: Model-First e Code-First

Introdução

Existem três tipos de abordagens quando estamos a utilizar Entity Framework 4.0: database-first onde são criadas as nossas entidades (classes) usando uma base de dados já existente; model-first onde é criado o nosso modelo conceptual e, com base nele, é gerado um script para a criação da base de dados; e code-first onde é utilizado POCO (Plain Old Code CRL) para criação manual de toda a lógica de entidades e ligação, não perdendo no entanto, todas as vantagens da utilização do Entity Framework.

Na edição da Revista PROGRAMAR nº 26, de Dezembro de 2010, abordei a utilização do modelo database-first, mostrando como criar as entidades e como efectuar algumas operações CRUD (acrónico para Create, Read, Updade e Delete).

Neste artigo irei abordar de uma forma geral como utilizar as restantes abordagens: model-first e code-first.

Abordagem Model-First

Esta abordagem permite-nos criar o nosso modelo conceptual, usando o Visual Studio, e depois, com base neste, criar a base de dados. Após a criação do modelo é criada a DDL (Data Definition Language), que será guardado num ficheiro *.sql e que nos permite então criar a base de dados.

Existem algumas vantagens desta abordagem pois é uma forma de trabalhar onde temos o nosso modelo e não nos precisamos de preocupar com a base de dados ou como esta irá ser construída. Não necessitamos também de ter conhecimentos muito específicos de bases de dados (como criar tabelas, relações, etc.), sendo tudo feito no Visual Studio de uma forma simplificada. Além disso, ficamos com o DDL que nos permite criar a base de dados em qualquer altura (por exemplo após a instalação da aplicação).

Neste exemplo será criada uma Class Library, permitindo assim isolar a lógica de acesso a dados e, caso seja necessário, reutilizar em diferentes projectos.

Para a criação do nosso modelo, numa abordagem model-first, criamos um novo projecto no Visual Studio 2010 definindo como Framework a 4.0, e com o nome “RevistaClassLibrary”.

NOTA: Após o projecto criado podemos apagar a classe que aparece por defeito (Class1 .vb) pois não será necessária.

Adicionamos um novo item, recorrendo aos templates no separador Data - ADO.NET Entity Data Model. Esta opção, que iremos definir com o nome RevistaModel.edmx, irá criar um ficheiro *.edmx que irá representar o nosso modelo.

Este *.edmx é um ficheiro XML que define o modelo conceptual, o modelo de dados e as relações entre as diferentes entidades. Na seguinte opção, podemos escolher se queremos gerar um modelo de uma base de dados, como foi abordado no artigo anterior na Revista PROGRAMAR edição 26, ou criar um modelo vazio. Iremos escolher a segunda opção – Empty model.

Com o nosso documento criado, ainda vazio, existem duas ferramentas importantes para o desenvolvimento do modelo: a Toolbox, que tem agora objectos específicos para o Entity Framework e o Model Browser que permite explorar o nosso modelo. Existem duas formas de criar o modelo: através da Toolbox, já referida anteriormente, ou clicando com o botão direito do rato sobre a janela aberta. Esta segunda opção é mais simples de utilizar.

Ainda antes de iniciarmos a construção do nosso modelo conceptual, existe uma opção interessante, se olharmos para a janela das propriedades: Pluralize New Objects. Esta opção, caso esteja definida como verdadeira (True), irá automaticamente tentar pluralizar os nomes das entidades. Infelizmente não funciona na versão Portuguesa, mas se utilizarmos nomes em Inglês, é muito interessante.

Para este exemplo vamos então criar um modelo muito simplificado que permita representar as edições da revista PROGRAMAR. Vamos criar duas entidades que vão representar os artigos e os seus autores.

Por defeito, quando criamos uma nova entidade, ele inclui a criação de um identificador (chave primária), que podemos, caso não seja necessário, retirar. Não define também nenhuma herança, podendo esta ser indicada no “Base Type”, ou seja, podemos definir heranças entre entidades, seleccionado a entidade correspondente. Adicionando algumas propriedades, e definindo os tipos de dados correctos (ex. DataNascimento = DateTime ou Edicao = Int32), rapidamente construímos os modelos para representar as edições da revista.

De notar que por defeito, quando é adicionada uma nova propriedade à entidade, o tipo de dados está definido como String, com um tamanho de armazenamento máximo para este tipo de dados (2^3-1) - nvarchar(max). Podemos e devemos alterar, caso seja necessário, assim como explorar e ajustar as restantes propriedades, como por exemplo, o tamanho máximo para uma String (Max Lenght), qual o valor por defeito (DefaultValue), se permite valores nulos (Nullable), etc.

E já estão então criadas as duas entidades e neste momento só nos falta definir a relação entre ambas. Como um artigo pode ter vários autores e um autor pode ter vários artigos, necessitamos de criar uma relação muitos para muitos (many-to-many).

Ao adicionarmos a relação entre as entidades, usando a opção Association, é criado um novo campo no final, designado por Navigation Property, que irá permitir a navegação entre as entidades. Podemos alterar o nome da propriedade de navegação (caso seja necessário).

E já está! Este foi o último passo para criar o modelo conceptual e é agora altura de gerar a base de dados. Para o fazer é só necessário clicar com o botão direito do rato sobre o editor e seleccionar a opção “Generate Database from Model”.

Irá então aparecer um wizard que nos permite seleccionar uma ligação já existente ou criar uma nova.

Seleccionada a ligação que pretendemos, irá ser gerado um script DDL que permitirá, após execução, criar uma base de dados em SQL Server 2005, 2008 e Azure.

Reparem que apenas criamos duas entidades (autores e artigos), mas como definimos uma relação muitos para muitos (many-to-many), é necessário utilizar uma tabela auxiliar. O EF fez isso por nós e no SQL ficamos então com três tabelas, como se pode ver na seguinte imagem:

Se no Solution Explorer escolhermos a opção “Show All Files”, podemos ver que o nosso modelo (*.edmx) tem um ficheiro com a extensão *.vb (neste caso RevistaModel.Designer.vb) . Neste ficheiro podemos ver e o código que está por detrás do nosso modelo conceptual, e efectuar eventualmente, algumas alterações.

Ao adicionarmos um novo projecto a esta solução (*.sln), que irá representar a camada de apresentação (Presentation Tier), ou usando externamente, é necessário adicionar referências à classe que criamos (separador Project) e a System.Data.Entity (separador .NET). É necessário também copiar a Connection String, que se encontra no ficheiro de configuração (app.config ou web.config), uma vez que esta foi definida na Class Library, no momento de ligação à base de dados.

<connectionStrings> <add name="RevistaModelContainer" connectionString="
metadata=res://*/RevistaModel.csdl|res://*/RevistaModel.ssdl|
res://*/RevistaModel.msl; provider=System.Data.SqlClient;
provider connection string=&quot; Data Source=.;Initial Catalog=master;Integrated Security=True; MultipleActiveResultSets=True&quot; "providerName="System.Data.EntityClient" />

Connection String tem um conjunto de metadata que indica a localização do ficheiro de CSDL (Conceptual Schema Definition Language), do SSDL (Store Schema Definition Language) e do MSL (Mapping Schema Language). O asterisco (*) indica que estes ficaram embebidos no ficheiro binário, podendo isto ser alterado, indicando nas propriedades do modelo conceptual, que o Metadata Artifact Processing não esta Embed in Output Assembly mas sim Copy to Output Directory. Indica depois a ligação propriamente dita à base de dados.

Abordagem Code-First

Esta é outra abordagem que podemos utilizar em Entity Framework, além das já referidas neste artigo (model-first) e no artigo da edição 26 da revista PROGRAMAR (database-first).

Uma das vantagens do code-first (ou como é também designado code-only), utilizando POCO (Plain Old CLR objects ), é que não ficamos “presos” ao Entity Framework, pois todas as classes geradas automaticamente herdam da classe EntityObject. Além disso utilizamos as classes que queremos, com muito menos código (um exemplo mesmo pequeno como este tem mais de 300 linhas de código), o torna a manutenção da aplicação muito mais simples.

Para usar esta abordagem, onde somos nós que desenhamos as classes que vão representar as entidades, podemos seleccionar o nosso modelo conceptual (*.edmx) e na janela de propriedades, na opção “Code Generation Strategy”, que está definida para Default, seleccionamos None. Isto fará com que o código gerado automaticamente seja apagado, possibilitando desta forma o desenvolvimento personalizado.

Para representar o modelo conceptual mostrando anteriormente, e tendo em conta que este é um exemplo muito simples (para efeitos de demonstração apenas), necessitamos apenas de três classes: Artigo, Autor e RevistaModelContainer.

As duas primeiras classes ( Artigo e Autor), vão representar as duas entidades e definem as propriedades da classe e a associação entre ambas (usando uma ICollection). Podemos ter mais propriedades e mais métodos nas classes, mas para que isto funcione, temos de ter pelo menos as que estão definidas no modelo.

Imports System.Collections
Imports System.Data.Objects

Public Class Artigo

  Public Property Id As Integer
  Public Property Titulo As String
  Public Property Texto As String
  Public Property Edicao As Integer

  ' Overridable para permitir o LazyLoading
  Public Overridable Property Autores() As ICollection(Of Autor)

  Sub New()
    Autores = New List(Of Autor)
  End Sub

End Class


Public Class Autor

  Public Property Id As Integer
  Public Property Nome As String
  Public Property DataNascimento As DateTime

  ' Overridable para permitir o LazyLoading
  Public Overridable Property Artigos() As ICollection(Of Artigo)

  Sub New()
    Artigos = New List(Of Artigo)
  End Sub

End Class

IMPORTANTE: A declaração de variáveis em Visual Basic não é, como sabem, case sensitive. No entanto, na declaração das propriedades das entidades (classes) é obrigatório que se declarem de acordo com o modelo (*.edmx), ou seja, há distinção entre maiúsculas e minúsculas.

A terceira classe é onde se define o nosso Container, que herdas do ObjectContext, ou seja, é onde criamos a ligação entre o Entity Framework e as nossas classes anteriores. O ObjectSet é novo na versão 4.0 do Entity Framework e permite-nos trabalhar os dados como colecções, permitindo também executar queries.

Public Class RevistaModelContainer
  Inherits ObjectContext

  Sub New()
    ' Indica a ConnectionString (ver em app.config) e nome do Container
    MyBase.New("name=RevistaModelContainer", "RevistaModelContainer")

    ' Cria as instancias dos ObjectSets
    _Artigos = MyBase.CreateObjectSet(Of Artigo)("Artigos")
    _Autores = MyBase.CreateObjectSet(Of Autor)("Autores")

    ' Define que o LazyLoading está
    ' activo (por defeito não está)
    MyBase.ContextOptions.LazyLoadingEnabled = True
  End Sub

  Private _Artigos As ObjectSet(Of Artigo)
  Public ReadOnly Property Artigos() As ObjectSet(Of Artigo)
    Get
      Return _Artigos
    End Get
  End Property

  Private _Autores As ObjectSet(Of Autor)
  Public ReadOnly Property Autores() As ObjectSet(Of Autor)
    Get
      Return _Autores
    End Get
  End Property

End Class

Como é possível ver neste código, habilitamos a opção LazyLoadingEnable do ObjectContext, colocando-a a True. O Lazy Loading permite que as entidades relacionadas sejam automaticamente carregadas da fonte de dados quando acedemos às propriedades de navegação (neste caso Autores e Artigos).

E é tudo! Com poucas linhas de código criamos as nossas classes, que definem as nossas entidades, e criamos o nosso Container que permite interligar as classes com o Entity Framework.

Mas este é apenas um exemplo bastante simples e caso usássemos um modelo complexo, com inúmeras entidades e associações, era muito trabalhoso criar todas estas classes POCO.

Por isso o Entity Framework permite a utilização/criação de templates que geram o código por nós. São designados por T4 (Text Template Transformation Toolkit) Text Templates e são ficheiros de texto com uma extensão *.tt . Existe um template para a criação de classes POCO. Não está disponível nos templates do Visual Studio 201 0, mas se abrirmos o modelo conceptual e seleccionarmos “Add Code Generation Item”, podemos pesquisar no Online Templates e instalar.

Após a rápida instalação, podemos então seleccionar ADO.NET POCO Entity Generator.

Isto irá adicionar dois ficheiros *.tt ao projecto: POCOModel.tt e POCOModel.Context.tt. O POCOModel tem as classes que representam as entidades e o POCOModel.Context tem as classe de contexto.

NOTA: Ao adicionarmos os templates ao projecto, todo o código de Entity Framework será apagado. Desta forma, e muito rapidamente, criamos as nossas classes POCO usando estes templates.

Como foi possível ver ao longo deste artigo, e do artigo da edição nº 26 da revista PROGRAMAR, existem diferentes abordagens para a utilização do Entity Framework 4.0, permitindo criar um modelo relacional de uma base de dados, criar um modelo e com base neste criar a base de dados ou criando as nossas classes (entidades) usando POCO, ficando desta forma independentes e com a possibilidade de uma maior personalização de toda a lógica. A existência de templates permite simplificar o processo de criação de classes POCO e inclusive criar os nossos próprios templates.

No momento da criação deste artigo está já disponível o Entity Framework 4.1 Release Candidate que tem como principal novidade a DbContext API, que é uma abstracão simples do ObjectContex e que pode ser utilizada em qualquer abordagem (Database-First, Model-First e Code-First). Existe também algumas alterações na abordagem Code-First.

Alguns endereços interessantes:

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

Beginner's Guide to the ADO.NET Entity Framework
http://msdn.microsoft.com/en-us/data/ee712907

EF 4.1 Release Candidate Available
http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-release-candidate-available.aspx

EF 4.1 Model & Database First Walkthrough
http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-model-amp-database-first-walkthrough.aspx

EF 4.1 Code First Walkthrough
http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-code-first-walkthrough.aspx

 







Este artigo está disponível na revista PROGRAMAR Nº 28 de Abril de 2011, entre muitos outros artigos de programação!


Microsoft All-In-One Code Framework

A Microsoft All-In-One Code Framework é uma biblioteca de exemplos gratuitos de aplicações .NET (VB.NET, C# e C++), categorizados em diversas áreas de desenvolvimento, para as versões do Visual Studio 2008 e 2010.

Existem diversos exemplos de áreas como ASP.NET, Silverlight, Windows Azure, Office, Windows 7, Windows Forms, WPF, XML, Segurança, entre muitas outras.

A Microsoft Community Team recolhe informação de necessidades frequentes e prepara exemplos com as melhores praticas de desenvolvimento. Todos podem contribuir com pedidos de exemplos ou votando nos pedidos já efectuados.

Está disponível ainda um ficheiro *.docx com os Coding Standards utilizados nos exemplos, com algumas boas referências e bases a seguir nas aplicações.

Mais informação e downloads: http://1code.codeplex.com/
Para acompanhar as novidades pode seguir o blog: http://blogs.msdn.com/b/codefx/


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


Aplicações para Windows Phone já disponíveis com Visual Basic

Foi hoje lançado um conjunto de ferramentas que permitem também (uma vez que já estava disponível para C# e XNA) a todos os programadores que utilizam Visual Basic e Silverlight, desenvolver aplicações para o Windows Phone 7.

Pré-requisitos:
- Windows Phone Developer Tools RTW
- Visual Studio 2010 Professional ou superior

Para já não suporta projectos XNA e não permite integrar com o Expression Blend.

Download: Microsoft Visual Basic CTP for Windows Phone Developer Tools.

Anuncio oficial, recursos, imagens e alguns exemplos: Visual Basic Team Blog


VB.NET: Como abrir ficheiros de texto delimitados

Os ficheiros de texto são cada vez menos usados, mas ainda há alguns casos que se utilizam, como por exemplo, para a criação de ficheiros log, ficheiro CSV (Comma-separated values), etc.

Para ler ficheiros de texto existem vários métodos, alguns dos quais referidos num artigo anterior, mas quando são listas a forma mais fácil, rápida e prática de o fazer é utilizando uma ligação Microsoft Jet OLE DB 4.0.

Imaginemos o seguinte ficheiro (dados.csv):

1;Amarelo;22:09 11-06-2010
2;Azul;22:10 12-06-2010
3;Verde;22:11 12-06-2010
4;Verde;22:12 13-06-2010
5;Preto;22:13 14-06-2010
6;Branco;22:14 14-06-2010

Para ler este ficheiro é apenas necessário:

' ConnectionString para ligação Microsoft Jet OLEDB
Dim connString As String =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\;" &
    "Extended Properties='text;HDR=no;FMT=Delimited'"

Dim SQL As String = "SELECT * FROM dados.csv"
Using da As New OleDb.OleDbDataAdapter(SQL, connString)
    Dim ds As New DataSet
    da.Fill(ds)

    Stop ' Informação disponível no DataSet

End Using

Desta forma colocamos toda a informação num DataSet. Neste exemplo, a DataTable terá 6 linhas (rows) e três colunas (columns), onde as colunas terão o nome, gerado automaticamente, de “F1”, “F2” e “F3”.

Depois é fácil filtrar os dados! Por exemplo, para mostrar todos os registos que tenham na segunda coluna o valor “Verde”:

' ConnectionString para ligação Microsoft Jet OLEDB
Dim connString As String =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\;" &
    "Extended Properties='text;HDR=no;FMT=Delimited'"

Dim SQL As String = "SELECT * FROM dados.csv"
Using da As New OleDb.OleDbDataAdapter(SQL, connString)
    Dim ds As New DataSet
    da.Fill(ds)

    Dim view As DataView = ds.Tables(0).DefaultView
    view.RowFilter = "F2 = 'Verde'"

    ' Mostra o número das linhas que têm o
    ' valor “Verde’ na segunda coluna      
    For x As Integer = 0 To view.Count - 1
        Console.WriteLine(view(x).Row.Item(0).ToString)
    Next
    Console.Read()

End Using

Neste exemplo foi utilizado um DataView, mas podia ser feito directamente na instrução SQL:

"SELECT * FROM dados.csv WHERE F2 = 'Verde'"

Mas imaginemos que o ficheiro tem um delimitador diferente, ou seja, não é utilizado o ponto e virgula (;) mas sim outro. Isto poderá acontecer por diversos motivos, com por exemplo, quando o ficheiro é gerado por uma máquina ou quando é gerado por uma aplicação que não temos controlo.

Imaginemos agora que o delimitador e uma barra (|).

1|Amarelo|22:09 11-06-2010
2|Azul|22:10 12-06-2010
3|Verde|22:11 12-06-2010
4|Verde|22:12 13-06-2010
5|Preto|22:13 14-06-2010
6|Branco|22:14 14-06-2010

Se executássemos o código anterior, iria ler o ficheiro como uma coluna apenas. 

Uma solução para resolver este problema seria a de utilizar um ficheiro de schema, com o nome schema.ini, que seria colocado na mesma directoria do ficheiro a ler. Este ficheiro fornece o IISAM com informações sobre o formato dos dados, o nome da coluna e informações sobre o tipo de dados, e várias outras características, permitindo também definir qual o delimitador.

A estrutura(simplificada) é a seguinte:

[nome do ficheiro]
Format=Delimited(delimitador)
ColNameHeader=True ou False

Para o exemplo apresentado, o ficheiro schema.ini ficaria da seguinte forma:

[dados.csv]
Format=Delimited(|)
ColNameHeader=False

Desta forma podemos ler o ficheiro indicando qual o delimitador correcto e definindo ainda algumas informações adicionais.


VS 2010 Keyboard Shortcut Posters

Já estão disponíveis à algum tempo a lista dos atalhos do teclado para o Visual Studio (Visual Basic, C#, F# e C++). Para quem ainda não tem, pode descarregar os PDF’s e ver todas as opções disponível.

VISUAL BASIC

VISUAL C#

VISUAL F#

VISUAL C++


VS2010: Parallel Extensions - Tasks e Task(Of TResult)

O namespace System.Threading.Tasks trás alguns métodos que permitem realizar tarefas de forma assíncrona e de uma forma bastante simples de implementar. Dos novos métodos/tipos deste namespace, podem destacar-se 3:

Nota: Neste artigo serão focados apenas os dois primeiros.

Para o seguinte exemplo importar os seguinte namespaces:

Imports System.Threading
Imports System.Threading.Tasks

De uma forma geral uma Task funciona do seguinte modo:

        ' Define uma nova Task utilizando uma expressão Lambda
        ' que não será executada automáticamente após a declaração
        Dim t1 As New Task(Sub()
                               For x As Integer = 0 To 50
                                   Console.WriteLine("t1 - " & x.ToString())
                                   Thread.Sleep(200)
                               Next
                           End Sub)

        ' Inicia a Task
        t1.Start()
        Console.WriteLine("Tasks1 iniciada!")


        ' Define uma Action Delegate que irá encapsular um método
        Dim doSomething As New Action(Sub()
                                          For x As Integer = 0 To 50
                                              Console.WriteLine("t2 - " & x.ToString())
                                              Thread.Sleep(200)
                                          Next
                                      End Sub)

        ' Define uma nova Task e inicia-a
        Dim t2 As New Task(doSomething)
        t2.Start()
        Console.WriteLine("Tasks2 iniciada!")


        ' Aguarda que as tasks terminem antes de continuar
        Tasks.Task.WaitAll(New Task() {t1, t2})
        Console.WriteLine("Tasks terminadas!")

Este exemplo mostra como criar uma tarefa simples, usando uma Lambda Expression, e usando um Action Delegate. Mostra também como usar o método WaitAll() e com isso esperar que todas as tarefas terminem antes de avançar com o código.

Mas por uma questão de performance é aconselhado que se utilize o seguinte método para a criação de tarefas:

        ' Define uma nova Task, usando o método Factory.StartNew()
        Dim t3 As Task = Task.Factory.StartNew(doSomething)
        Console.WriteLine("Tasks3 iniciada!")

Este método cria uma tarefa e inicia-a imediatamente, não podendo no entanto ser usado em algumas situações (como por exemplo caso a tarefa necessite de ser executada posteriormente).


Mas todos estes exemplos não retornam valores! É muitas vezes necessário receber informação de uma determinada tarefa e nestes casos podemos utilizar o método Tasks.Task(Of TResult).

Eis um exemplo da sua utilização, que serve unicamente para mostrar como receber um resultado de uma tarefa, uma vez que não é um exemplo que necessite de ser executado desta forma.

        'Utiliza uma task para recolher o nome de todos os paises
        Dim countries = Task.Factory.StartNew(Of List(Of CultureInfo))(
                Function()
                    Return CultureInfo.GetCultures(CultureTypes.AllCultures).ToList()
                End Function)

        ' Espera que a task complete de modo a
        ' garantir que tem todos os resultados
        countries.Wait()

        ' Mostra todos os paises de língua Inglesa
        For Each item As CultureInfo In
                countries.Result.Where(Function(c) c.Name.Contains("en") And
                                           c.Name.Length > 2)
            Console.WriteLine(item.NativeName)
        Next

        Console.ReadKey()

Este exemplo, onde é necessário importar os namespaces System.Threading.Tasks e System.Globalization, recolhe a lista de todos os países, espera que a tarefa termine, e depois, usando Lambda Expressions, filtra todos os países de língua inglesa. O resultado, ou seja, o valor produzido e que será devolvido, é obtido através da propriedade Result.

Como a opções Option Infer está definida como On, não é necessário declarar a variável “countries” explicitando o tipo, uma vez que é inferido o tipo correcto(simplificando desta forma o código). Neste caso seria:

Dim countries As Task(Of List(Of CultureInfo)) = ...

Como podem ver nos exemplos mostrados, a criação de tarefas em paralelo é bastante simples e está bastante optimizada no Visual Studio 2010/.NET Framework 4.0.


VS2010 RC1: Task Parallel Library – Parallel.Invoke()

Nos artigos anteriores sobre a Task Parallel Library (TPL) foram referidos os métodos Parallel.For e Parallel.ForEach que servem essencialmente para criar ciclos que podem correr em paralelo. Este método, o Parallel.Invoke, serve para executar processos que decorrem eventualmente em paralelo.

Quando os processos são invocados, são separados nos diversos núcleos do processador e o código só avança quando todos tiverem terminado.

Eis um exemplo do funcionamento:

Imports System.Threading
Imports System.Threading.Tasks

Module Module1

  Private Sub task1()
    For x As Integer = 0 To 50
      Console.WriteLine("Task1 - {0}", x.ToString())
      System.Threading.Thread.SpinWait(50000000)
    Next
  End Sub

  Private Sub task2()
    For x As Integer = 0 To 50
      Console.WriteLine("Task2 - {0}", x.ToString())
      System.Threading.Thread.SpinWait(50000000)
    Next
  End Sub

  Sub Main()

    ' Chama as diversas acções (incluindo uma Lambda)
    Dim actions() As Action = {AddressOf task1, AddressOf task2,
                                 Sub()

                                   ' Usando uma Lambda Expression
                                   For x As Integer = 0 To 50
                                     Console.WriteLine("Task3 - {0}", x.ToString())
                                     System.Threading.Thread.SpinWait(50000000)
                                   Next

                                 End Sub}

    Parallel.Invoke(actions)

    Console.WriteLine("Acções completas!")

  End Sub

End Module

Executando o mesmo, mas sequencialmente (onde o tempo de execução é significativamente superior):

Imports System.Threading
Imports System.Threading.Tasks

Module Module1

  Private Sub task1()
    For x As Integer = 0 To 50
      Console.WriteLine("Task1 - {0}", x.ToString())
      System.Threading.Thread.SpinWait(50000000)
    Next
  End Sub

  Private Sub task2()
    For x As Integer = 0 To 50
      Console.WriteLine("Task2 - {0}", x.ToString())
      System.Threading.Thread.SpinWait(50000000)
    Next
  End Sub

  Sub Main()

    task1()
    task2()

    For x As Integer = 0 To 50
      Console.WriteLine("Task3 - {0}", x.ToString())
      System.Threading.Thread.SpinWait(50000000)
    Next

  End Sub

End Module

E é o terceiro e último evento da classe Parallel. Como se pode ver nos exemplos apresentados(For, ForEach e Invoke), são muito simples de utilizar e vai de certeza ajudar a melhorar o desempenho das aplicações.


VS2010 RC1: Task Parallel Library – Parallel.ForEach()

Este método executa um ciclo semelhante à instrução For Each, mas que possibilita a execução em paralelo. É muito semelhante ao exemplo do artigo anterior, mas difere do Parallel.For() pois é usado quando os dados são colecções ou arrays.

Eis um exemplo da sua implementação/utilização:

Imports System.Threading
Imports System.Threading.Tasks

Module Module1

  Sub Main()
    Dim result1, result2 As Long
    Dim values = Enumerable.Range(0, 49)

    Dim sw As New Stopwatch
    sw.Start()

    ' ------------------------------------------------
    ' Ciclo For Each
    ' ------------------------------------------------
    For Each value As Integer In values
      Console.WriteLine("Value:{0} GUI:{1}", value.ToString(), Guid.NewGuid())
      Thread.SpinWait(50000000)
    Next

    result1 = sw.ElapsedMilliseconds

    sw.Restart() ' <- novo método no Visual Studio 2010

    ' ------------------------------------------------
    ' Ciclo Parallel.ForEach
    ' ------------------------------------------------
    Parallel.ForEach(values, Sub(value)
                               Console.WriteLine("Value:{0} GUI:{1}",
                                                 value.ToString(),
                                                 Guid.NewGuid())
                               Thread.SpinWait(50000000)
                             End Sub)

    result2 = sw.ElapsedMilliseconds
    sw.Stop()

    Console.WriteLine("Tempo de execução 'For Each' {0} ms", result1)
    Console.WriteLine("Tempo de execução 'Parallel.ForEach' {0} ms", result2)
    Console.ReadKey(True)

  End Sub

End Module

E os resultados são uma vez mais significativos:

É mais um ciclo disponível da Task Parallel Library (TPL) – Parallel Extensions, que quando bem aplicado pode melhorar bastante o desempenho da aplicação.




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