Microsoft apresenta versão 11 do Visual Studio

Deixe um comentário

A cada lançamento do Visual Studio, normalmente são apresentadas novas características tanto no seu IDE, quanto no suporte de linguagens de programação. O vice-presidente da divisão de desenvolvimento da Microsoft apresentou recentemente quais as mudanças que vão entrar no Visual Studio 11.

A nova versão dará pleno reconhecimento à linguagem JavaScript, assim como faz com as linguagens C#, Visual Basic e C++. As melhorias para JavaScript também incluem suporte para a linguagem ECMAScript 5 como padrão, e o suporte para remover bugs para JavaScript agora coincide com o que está previsto outras linguagens do Visual Studio, incluindo janelas de remover bugs que suportam interagir com o aplicativo que está sendo debugado. Talvez, a novidade mais interessante seja a adição de um REPL (Read-Evaluate-Print Loop) para o desenvolvimento JavaScript.

O suporte de programação assíncrona serão integrados ao C # 5 e ao Visual Basic 11. O uso de código assíncrono em versões anteriores do Visual Studio foi difícil de se implementar e debugar. No Visual Studio 11, ambas as áreas serão melhoradas, fornecendo novos recursos de linguagem que permitem o uso de fluxos de controle tradicionais (loops, condicionais etc) com código assíncrono e inclui a capacidade de debugar essas declarações com o removedor de bugs integrado.

O desenvolvimento com C++ deve receber diversas melhorias notáveis na nova versão, como, por exemplo, melhor suporte IDE e a capacidade de construir aplicativos nativos do Windows Metro. Há uma maior ênfase no suporte para escrever o código paralelo utilizando o C++ e a tecnologia AMP (Accelerated Massive Parallelism). O Visual Studio 11 permite debugar diretamente os aplicativos usando o C++ e a AMP.

A nova versão do Visual Studio vai introduzir o F# 3.0 e a funcionalidade Type Provider. Esse mecanismo tem evoluído em resposta à necessidade de ligar linguagens estaticamente tipadas (F #) para os dados cada vez mais dinâmicos encontrados na web. O F# 3.0 terá suporte para Odata, WSDL e SQL, mas provedores customizados podem ser escritos.

Fonte: iMasters

Links relacionados:

Anúncios

Visual Studio LightSwitch

Deixe um comentário

A Microsoft liberou para a comunidade do MSDN em 18/09 o download do Visual Studio LightSwitch na versão beta, que promete permitir que usuários não desenvolvedores criem aplicações windows, web e nas nuvens. Além disso, é possível utilizar VB.Net e C# nas aplicações.

O Visual Studio LightSwitch utiliza modelos e outros componentes que facilitam a criação de aplicações para PCs, para a Web e para a nuvem e, em muitos casos, não requer que o usuário tenha que lidar com o código durante o processo.

De acordo com a Microsoft, os usuários do LightSwitch podem usar o Visual Basic ou C# para as aplicações e podem até mesmo conectar suas aplicações ao Excel, SharePoint ou aos serviços do Windows Azure.

Além disso, os usuários podem criar suas aplicações para que elas sejam executadas em qualquer ambiente compatível com o Silverlight: navegadores (Internet Explorer, Safari, Firefox), em PCs com o Windows ou no Windows Azure, por exemplo.

Embora o Visual Studio LightSwitch Beta 1 esteja disponível hoje para os assinantes da MSDN, ele será disponibilizado para download público apenas na próxima segunda-feira, 23 de agosto, através do LightSwitch Developer Center.

Fonte: Baboo

Saiba mais:

Trabalhando com tipos anuláveis

Deixe um comentário

Existem algumas situações onde precisamos estabelecer que uma variável pode ser nula. Isso acontece com muita frequência quando utilizando Modelos Objeto-Relacional, onde uma “cópia” da estrutura das tabelas da base de dados é feita dentro do modelo gerado no Visual Studio em forma de classes. Declarar variáveis como anuláveis é extremamente simples, e pode ser feito assim:

// C# - Pode ser assim
System.Nullable<decimal> decimalAnulavel = null;
System.Nullable<int> inteiroAnulavel = null;
System.Nullable<bool> booleanAnulavel = null;
// C# - Ou assim
decimal? decimalAnulavel = null;
int? inteiroAnulavel = null;
bool? booleanAnulavel = null;
' VB.NET - Existe uma única maneira
Dim decimalAnulavel As Nullable(Of Decimal) = Nothing
Dim inteiroAnulavel As Nullable(Of Integer) = Nothing
Dim booleanAnulavel As Nullable(Of Boolean) = Nothing

Como exemplo, uma variável bool anulável pode receber True, False e Null.

Ao declarar uma variável como anulável, são habilitadas duas novas propriedades:
  • HasValue: determina se a variável anulável possue valor.
  • Value: contém o valor não nulo da variável

Essas duas propriedades pode ser usadas em conjunto, como o código a seguir demonstra.

// C#
if (decimalAnulavel.HasValue)
    Console.WriteLine(decimalAnulavel.Value.ToString());
else
    Console.WriteLine("Valor nulo");
' VB.NET
If (decimalAnulavel.HasValue) Then
    Console.WriteLine(decimalAnulavel.Value.ToString)
Else
    Console.WriteLine("Valor Nulo")
End If

O Operador ?? do C#

O operador ?? facilita a manipulação de tipos anuláveis. Com ele podemos informar um valor fixo caso a variável seja nula.

// C#
Console.WriteLine((decimalAnulavel ?? decimal.Zero).ToString());

No VB.NET é bem parecido, mas não existe o operador ??, então usa-se o próprio If.

' VB.NET
Console.WriteLine((If(decimalAnulavel, Decimal.Zero)).ToString())

O Operador ?: do C#

O operador ?: funciona como um If, com a sintaxe (condicao ? true : false).

// C#
Console.WriteLine((decimalAnulavel.HasValue ?
                   decimalAnulavel.Value.ToString() :
                   "Valor nulo"));

No VB.NET é bem parecido, mas não existe o operador ?:, então usa-se o próprio If.

' VB.NET
Console.WriteLine((If(decimalAnulavel.HasValue, _
                      decimalAnulavel.Value.ToString(), _
                      "Valor nulo")))

Saiba mais:

Obrigado.

Exemplo de Implementação de IDisposable

3 comentários

A interface IDisposable é usada para liberar recursos. O garbage collector (coletor de lixo) libera automaticamente a memória alocada para um objeto gerenciado quando este objeto não estiver mais sendo utilizado. No entanto, não é possível prever quando esta coleta de lixo irá ocorrer. Além disso, o garbage collector não tem conhecimento dos recursos não gerenciados.

Usamos o método Dispose desta interface para liberar explicitamente recursos não gerenciados em conjunto com o garbage collector. O consumidor de um objeto pode chamar esse método quando o objeto não for mais necessário.

Inicialmente, precisamos fazer a classe que queremos implementar IDisposable herdar desta interface.

// C#
public class GerenciarClientes : IDisposable
{
    public void Dispose()
    {

    }
}

 

' VB.NET
Public Class GerenciarClientes
    Implements IDisposable

    Public Overridable Sub Dispose() Implements IDisposable.Dispose

    End Sub
End Class

OBS: Em C#, para que o próprio Visual Studio implemente o método Dispose, basta clicar com o botão direito do mouse sobre a interface, escolher a opção ‘Implement Interface’ e ‘Implement Interface’ novamente. Esse mesmo procedimento funciona com a implementação de qualquer interface em uma classe.

Para controlarmos corretamente a liberação dos recursos, é necessário criar uma variável do tipo booleana, que indicará se o método Dispose já foi disparado.

Além disso, precisamos criar um método privado que será chamado de lugares distintos e controlará quais recursos (gerenciados ou não) devem ser liberados.

// C#

// booleano para controlar se
// o método Dispose já foi chamado
bool disposed = false;

// método privado para controle
// da liberação dos recursos
private void Dispose(bool disposing)
{
    // Verifique se Dispose já foi chamado.
    if (!this.disposed)
    {
        if (disposing)
        {
            // Liberando recursos gerenciados

        }

        // Seta a variável booleana para true,
        // indicando que os recursos já foram liberados
        disposed = true;
    }
}

 

' VB.NET

' booleano para controlar se
' o método Dispose já foi chamado
Private disposed As Boolean = False

' método privado para controle
' da liberação dos recursos
Private Sub Dispose(ByVal disposing As Boolean)
    ' Verifique se Dispose já foi chamado.
    If Not Me.disposed Then
        If disposing Then
            ' Liberando recursos gerenciados

        End If

        ' Seta a variável booleana para true,
        ' indicando que os recursos já foram liberados
        disposed = True
    End If
End Sub

Dentro do método público Dispose, é necessário chamar o método privado Dispose e também informar o garbage collector para não chamar o método finalizador da classe, pois estamos controlando isso manualmente. Para isto, utilizamos o método GC.SuppressFinalize().

// C#
bool disposed = false;

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

 

' VB.NET
Dim disposed As Boolean = False

Protected Overridable Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
End Sub

Por fim, precisamos programar o método finalizador da classe, que é invocado pelo garbage collector para liberar os recursos. Toda liberacao implementada dentro dele só será executada quando o metodo for invocado, porém não conseguimos saber quando isto vai acontecer e recursos importantes podem ficar presos até que isto aconteça.

// C#
~GerenciarClientes()
{
    Dispose(false);
}
' VB.NET
Protected Overrides Sub Finalize()
    Dispose(False)
    MyBase.Finalize()
End Sub

Pronto, implementamos IDisposable. Com essa implementação, sempre que tivermos uma instância da classe que não será mais utilizada, devemos chamar o método Dispose ou envolvê-la em um bloco using.

// C#

// forma simples
GerenciarClientes g1 = new GerenciarClientes();

// código consumidor da instância

// Liberando o recurso
g1.Dispose();

// usando try...finally
GerenciarClientes g2 = new GerenciarClientes();
try
{
    // código consumidor da instância
}
finally
{
    g2.Dispose();
}

// ou com using
using (GerenciarClientes g3 = new GerenciarClientes())
{
    // código consumidor da instância
} // aqui o método Dispose é invocado

 

' VB.NET

' forma simples
Dim g1 As New GerenciarClientes()
' código consumidor da instância

' Liberando o recurso
g1.Dispose()

' usando Try...Finally
Dim g2 As New GerenciarClientes()
Try
    ' código consumidor da instância
Finally
    g2.Dispose()
End Try

' ou com using
Using g3 As New GerenciarClientes()
    ' código consumidor da instância
End Using ' aqui o método Dispose é invocado


Referências

Código Fonte

O código fonte deste post pode ser baixado aqui.



Obrigado

Passar parâmetros para Threads

3 comentários

Há algum tempo, escrevi um post que mostra formas de programar threads em C# e VB.NET. Na ocasião, mostrei uma forma de passar parâmetros para uma thread. O intuito deste post é mostrar uma outra forma existente para este mesmo objetivo.

Primeiro, criamos uma classe que conterá propriedades que representarão os parâmetros que devem ser passados para a Thread.

// C#
public class DadosLog
{
    public Exception Exception { get; set; }
    public string StrNomeProjeto { get; set; }
    public string StrNomeClasse { get; set; }
    public string StrNomeMetodo { get; set; }
}
' VB.NET
Public Class DadosLog
    Public Property Exception() As Exception
        Get
            Return _Exception
        End Get
        Set(ByVal value As Exception)
            _Exception = value
        End Set
    End Property
    Private _Exception As Exception
    Public Property StrNomeProjeto() As String
        Get
            Return _StrNomeProjeto
        End Get
        Set(ByVal value As String)
            _StrNomeProjeto = value
        End Set
    End Property
    Private _StrNomeProjeto As String
    Public Property StrNomeClasse() As String
        Get
            Return _StrNomeClasse
        End Get
        Set(ByVal value As String)
            _StrNomeClasse = value
        End Set
    End Property
    Private _StrNomeClasse As String
    Public Property StrNomeMetodo() As String
        Get
            Return _StrNomeMetodo
        End Get
        Set(ByVal value As String)
            _StrNomeMetodo = value
        End Set
    End Property
    Private _StrNomeMetodo As String
End Class

Em seguida, o método que executará o processo em segundo plano deve ter como parâmetro de entrada um object.

// C#
public void ExecutarLogErro(object _dadosLog)
{
    DadosLog dadosLog = (_dadosLog as DadosLog);

    // Gravar Log no Repositório ou no Log de Eventos do Windows
}
' VB.NET
Public Sub ExecutarLogErro(ByVal _dadosLog As Object)
    Dim dadosLog As DadosLog = TryCast(_dadosLog, DadosLog)

    ' Gravar Log no Repositório ou no Log de Eventos do Windows
End Sub

Para concluir, passamos a instância da classe DadosLog no método Start() no momento da chamada à thread.

// C#
public void LogarErro(Exception exception,
    string strNomeProjeto,
    string strNomeClasse,
    string strNomeMetodo)
{
    DadosLog dadosLog = new DadosLog()
    {
        Exception = exception,
        StrNomeClasse = strNomeClasse,
        StrNomeMetodo = strNomeMetodo,
        StrNomeProjeto = strNomeProjeto
    };

    GerenciaLogErro gle = new GerenciaLogErro();
    Thread t = new Thread(gle.ExecutarLogErro);
    t.IsBackground = true;
    t.Start(dadosLog);
}
' VB.NET
Public Sub LogarErro(ByVal exception As Exception, _
                     ByVal strNomeProjeto As String, _
                     ByVal strNomeClasse As String, _
                     ByVal strNomeMetodo As String)
    Dim dadosLog As New DadosLog() With { _
     .Exception = exception, _
     .StrNomeClasse = strNomeClasse, _
     .StrNomeMetodo = strNomeMetodo, _
     .StrNomeProjeto = strNomeProjeto _
    }

    Dim gle As New GerenciaLogErro()
    Dim t As New Thread(AddressOf gle.ExecutarLogErro)
    t.IsBackground = True
    t.Start(dadosLog)
End Sub

Essa é apenas mais uma maneira de passar informações para a Thread. Existem outras e mais para frente tentarei demonstrar aqui.

OBS: Este código fonte pode ser baixado aqui.

Obrigado.

Entity Framework + TransactionScope

8 comentários

Antes de unir os dois assuntos, falarei um pouco de cada um para entendermos melhor a ideia deste artigo.

TransactionScope

Presente no .Net Framework desde a versão 2.0, TransactionScope fica disponível após adicionar referencia para System.Transactions, e fornece uma maneira simples de marcar um bloco de código como participante em uma transação, sem a necessidade de interagir com a transação em si. Um TransactionScope pode gerenciar o ambiente da transação automaticamente, inclusive transações de bancos de dados, como o Sql Server. A sintaxe de utilização é algo como isto:

// C#
using (TransactionScope scope = new TransactionScope())
{
    // Código que participa da transação

    scope.Complete();
} // Commit ou RollBack
' VB.NET
Using scope As New TransactionScope()
    ' Código que participa da transação

    scope.Complete()
End Using ' Commit ou RollBack

Mais detalhes sobre TransactionScope:
Classe TransactionScope
Enumerador TransactionScopeOption


Entity Framework

Acho que aqui não é necessário definir ou conceituar o Entity Framework, e sim, expor os motivos de usar o TransactionScope junto a ele. Se tiver interesse em ler conceitos sobre Entity Framework, clique aqui, aqui ou aqui.

Trabalhar com Entity Framework e um banco de dados de tamanho pequeno é simples, pois criamos o Modelo Objeto-Relacional (MOR) e já podemos sair desenvolvendo.  Quando temos um banco de dados muito grande, se colocarmos tudo em um único modelo, podemos ter diversos problemas, entre eles, desempenho e dificuldade em organização. Em geral, é recomendado ter modelos com até 100 entidades. Passando disso, já devemos começar a pensar em dividir em vários modelos.

NOTA: Utilizando apenas um modelo, todas as atualizações feitas através do Entity Framework já acontecem em uma transação, ou seja, se ocorrer algum erro antes que o método SaveChanges() esteja concluído, o RollBack é garantido. Neste caso, não é necessário usar uma transação explícita.

Aí vem a pergunta: E para controlar transações usando mais de um modelo? O intuído de escrever esse artigo é justamente estudar um pouco mais este assunto.


Transações usando mais de um Modelo Objeto-Relacional

Uma das maneiras de termos a mesma transação para mais de um modelo é usarmos o TransactionScope. A aplicação é simples e muito útil. Melhor do que escrever, é ir direto para o código.

// C#
using System;
using System.Transactions;
using EntityTransactionCS.Model1;
using EntityTransactionCS.Model2;

namespace EntityTransactionCS
{
    class Program
    {
        static void Main(string[] args)
        {
            bool bolSucesso = false;

            // Instanciando o Modelo1
            Modelo1 context1 = new Modelo1();

            // Instanciando o Modelo2
            Modelo2 context2 = new Modelo2();

            try
            {
                // Envolvendo o processo por um TransactionScope
                using (TransactionScope scope = new TransactionScope())
                {
                    // Inserindo Cliente com o Modelo1
                    Model1.CLIENTES cliente = new Model1.CLIENTES()
                    {
                        NM_CLIENTE = "Fernando Ottoboni",
                        NR_IDADE = 28
                    };

                    //context1.AddToCLIENTES(cliente);
                    context1.CLIENTES.AddObject(cliente);

                    // Inserindo Produto com o Modelo2
                    Model2.PRODUTOS produto = new Model2.PRODUTOS()
                    {
                        NM_PRODUTO = "Notebook DELL Inspiron 1564 4G 320GB.",
                        VL_PRECO = 2699
                    };
                    //context2.AddToPRODUTOS(produto);
                    context2.PRODUTOS.AddObject(produto);

                    try
                    {
                        // Salva as alterações realizadas no Contexto
                        context1.SaveChanges();
                        context2.SaveChanges();

                        bolSucesso = true;
                    }
                    catch
                    {
                        bolSucesso = false;
                    }

                    if (bolSucesso)
                    {
                        // Completa a transação (Fará o Commit)
                        scope.Complete();
                    }

                    // Somente depois de passar pelo Complete() que o
                    // TransactionScope fará o Commit.
                    // Caso contrário, o RollBack será executado.

                } // Commit ou RollBack

                if (bolSucesso)
                    Console.WriteLine("Dados gravados.");
                else
                    Console.WriteLine("Problemas ao gravar.");
            }
            finally
            {
                context1.Dispose();
                context2.Dispose();
            }

            Console.ReadKey();
        }
    }
}
' VB.NET
Imports EntityTransactionVB.EntityTransactionVB
Imports EntityTransactionVB.EntityTransactionVB.Model1
Imports EntityTransactionVB.EntityTransactionVB.Model2
Imports System.Transactions

Module Module1

    Sub Main()
        Dim bolSucesso As Boolean = False

        ' Instanciando o Modelo1
        Dim context1 As New Modelo1()

        ' Instanciando o Modelo2
        Dim context2 As New Modelo2()

        Try
            ' Envolvendo o processo por um TransactionScope
            Using scope As New TransactionScope()

                ' Inserindo Cliente com o Modelo1
                Dim cliente As New Model1.CLIENTES() With { _
                    .NM_CLIENTE = "Fernando Ottoboni", _
                    .NR_IDADE = 28 _
                }
                'context1.AddToCLIENTES(cliente)
                context1.CLIENTES.AddObject(cliente)

                ' Inserindo Produto com o Modelo2
                Dim produto As New Model2.PRODUTOS() With {
                    .NM_PRODUTO = "Notebook DELL Inspiron 1564 4G 320GB.", _
                    .VL_PRECO = 2699 _
                }
                'context2.AddToPRODUTOS(produto)
                context2.PRODUTOS.AddObject(produto)

                Try
                    ' Salva as alterações realizadas no Contexto
                    context1.SaveChanges()
                    context2.SaveChanges()

                    bolSucesso = True
                Catch
                    bolSucesso = False
                End Try

                If bolSucesso Then
                    ' Completa a transação (Fará o Commit)
                    scope.Complete()
                End If

                ' Somente depois de passar pelo Complete() que o
                ' TransactionScope fará o Commit.
                ' Caso contrário, o RollBack será executado.

            End Using ' Commit ou RollBack

            If bolSucesso Then
                Console.WriteLine("Dados gravados.")
            Else
                Console.WriteLine("Problemas ao gravar.")
            End If
        Finally
            context1.Dispose()
            context2.Dispose()
        End Try

        Console.ReadKey()
    End Sub

End Module


NOTA 1:Para excluir da transação uma determinada camada do código, utilize TransactionScopeOption.Supress na chamada ao construtor da classe TransactionScope.

// C#
using (TransactionScope scope =
    new TransactionScope(TransactionScopeOption.Suppress))
{
    // Código a ser suprimido
}
' VB.NET
Using scope As _
    New TransactionScope(TransactionScopeOption.Suppress)
    ' Código a ser suprimido
End Using


NOTA 2: TransactionScope pode ser utilizada com vários modelos de acesso a dados, inclusive providers que não são distribuídos pela Microsoft. Veja um exemplo utilizando SqlConnection:

// C#
using (TransactionScope scope = new TransactionScope())
{
    using (SqlConnection connection1 = new SqlConnection(connectString1))
    {
        connection1.Open();

        // Operações com connection1

        using (SqlConnection connection2 = new SqlConnection(connectString2))
        {
            connection2.Open();

            // Operações com connection2
        }
    }

    scope.Complete();
}
' VB.NET
Using scope As New TransactionScope()
    Using connection1 As New SqlConnection(connectString1)
        connection1.Open()

        ' Operações com connection1

        Using connection2 As New SqlConnection(connectString2)
            connection2.Open()

            ' Operações com connection2
        End Using
    End Using

    scope.Complete()
End Using



Conclusão

É de suma importância (e também uma boa prática) controlarmos transações em nossa aplicações. A classe TransactionScope nos fornece as ferramentas idais para isso e, quando aplicada em situações em que temos que quebrar o Modelo Objeto-Relacional e várias partes, facilita muito a nossa vida e dá todo o suporte que precisamos para manipulação de transações.


O download do código fonte pode ser feito aqui.


Obrigado

LINQ e Lambda Expression: OrderBy em vários campos

8 comentários

OBS: Para este artigo, estou levando em consideração o seguinte cenário:

Ordenar uma query por vários campos é algo comum e que todos nós, se já não precisamos, um dia precisaremos. Fazer isso com o LINQ é relativamente simples e pode ser algo desse tipo:

// C#
var produtos = from p in context.PRODUTOS
               orderby p.VL_PRECO, p.NM_PRODUTO
               select p;
foreach (var p in produtos)
{
    Console.WriteLine("{0}: {1}",
                      p.NM_PRODUTO,
                      ((decimal)p.VL_PRECO).ToString("N2"));
}
' VB.NET
Dim produtos = From p In context.PRODUTOS _
               Order By p.VL_PRECO, p.NM_PRODUTO _
               Select p
For Each p As PRODUTOS In produtos
    Console.WriteLine("{0}: {1}",
                      p.NM_PRODUTO,
                      CDec(p.VL_PRECO).ToString("N2"))
Next

No exemplo acima, é possível ver que basta enfileirar os campos que desejar ordenar, separados por vírgula, no Order By.

Como seria essa mesma ordenação usando Lambda Expression? A Lambda Expression nos oferece o extension method OrderBy(). Muita gente imagina que usando essa extensão seguidas vezes, ou seja, OrderBy().OrderBy(), resolverá o problema de ordenar por vários campos. Isso não acontece, pois as opções de ordem informadas no segundo OrderBy() substituem as opções do primeiro.

Ou então, usar o operador “&&” ou “And” entre as condições de ordenação. Isso também não funciona.

// C#
// forma errada: o segundo OrderBy substitui o primeiro
var produtos = context.PRODUTOS
                      .OrderBy(p => p.VL_PRECO)
                      .OrderBy(p => p.NM_PRODUTO);

// forma errada: colocar && entre as opções de ordenação não resolve
// essa forma gera erros em tempo de compilação e não executa a aplicação
var produtos = context.PRODUTOS
                      .OrderBy(p => p.VL_PRECO &&
                                    p.NM_PRODUTO);
' VB.NET
' forma errada: o segundo OrderBy substitui o primeiro
Dim produtos = context.PRODUTOS _
                      .OrderBy(Function(p) p.VL_PRECO) _
                      .OrderBy(Function(p) p.NM_PRODUTO)

' forma errada: colocar And entre as opções de ordenação não resolve
' essa forma gera erros em tempo de compilação e não executa a aplicação
Dim produtos = context.PRODUTOS _
                      .OrderBy(Function(p) p.VL_PRECO And _
                               Function(p) p.NM_PRODUTO)

O importante neste caso é saber o que a Lambda Expression com OrderBy() retornará um objeto do tipo IQueriable. A interface IQueriable implementa a interface IEnumerable que é normalmente utilizada ao criar um ObjectQuery. Já o OrderBy(), retorna um objeto IOrderedEnummerable que, por sua vez, disponibiliza novos extension methods, entre eles, ThenBy() e ThenByDescending().Isto significa que podemos ordenar com vários campos pela utilização de OrderBy() e ThenBy() juntos.

Veja no exemplo abaixo como seria a ordenação correta:

// C#
// forma correta: OrderBy().ThenBy()
var produtos = context.PRODUTOS
                      .OrderBy(p => p.VL_PRECO)
                      .ThenBy(p => p.NM_PRODUTO);

foreach (var p in produtos)
{
    Console.WriteLine("{0}: {1}",
        p.NM_PRODUTO,
        ((decimal)p.VL_PRECO).ToString("N2"));
}
' VB.NET
' forma correta: OrderBy().ThenBy()
Dim produtos = context.PRODUTOS _
                      .OrderBy(Function(p) p.VL_PRECO) _
                      .ThenBy(Function(p) p.NM_PRODUTO)

For Each p As PRODUTOS In produtos
    Console.WriteLine("{0}: {1}",
                      p.NM_PRODUTO,
                      CDec(p.VL_PRECO).ToString("N2"))
Next

É interessante ressaltar que essas mesmas regras valem para OrderByDescending() e ThenByDescending().

Código fonte

Este código fonte pode ser baixado aqui.

Older Entries