Um dos pilares do novo sistema operational da Microsoft, codename Longhorn, é o novo sistema de arquivos chamado WinFS. OPath é uma linguagem de consulta utilizada por WinFS para recuperar e selecionar objetos a partir de uma fonte de dados. Este artigo apresenta as razões para a criação de uma nova linguagem de consulta e introduz seus conceitos básicos. Serão apresentados também exemplos simples de filtros OPath que resultam em consultas de complexidade média.

Linguagem de Consulta

A OPath é chamada linguagem de consulta (Query Language), e não uma linguagem genérica de programação. O objetivo da linguagem OPath é permitir que o programador expresse com exatidão quais objetos deseja recuperar de uma base de dados. A OPath não apresenta, pelo menos por enquanto, nenhuma sintaxe para controle de fluxo (comandos do tipo IF, WHILE, entre outros) ou para criação de novos tipos e classes, aspectos típicos de uma linguagem de programação.

O membro mais famoso das linguagens de consulta é a linguagem SQL (Structured Query Language), amplamente adotada pela maioria dos bancos de dados relacionais. Um dos benefícios da linguagem SQL é possibilitar que o gerenciador de banco de dados receba um comando semelhante a Select ClienteID, Nome from Clientes e recupere as informações desejadas sem que o cliente tenha conhecimento dos detalhes de como tais informações foram armazenadas em disco ou recuperadas, qual o formato físico dos registros de cada tabela, qual a representação binária dos tipos de cada coluna e outras características que só importam ao gerenciador de banco de dados.

O proprietário da tabela Clientes tem a flexibilidade de adicionar ou remover colunas da tabela (exceto as colunas ClienteID e ClienteName), sem prejudicar a execução do comando. Cabe ao gerenciador de banco de dados encapsular toda a complexidade envolvida na persistência dos dados num disco rígido. Da mesma forma, a linguagem OPath possibilita encapsular toda a complexidade envolvida na persistência de objetos na camada de persistência de objetos, o que permite maior flexibilidade para o programador. Na seção abaixo, veremos no que consiste esta complexidade.

Classes e Tabelas

A adoção de linguagens de programação orientadas a objeto é inquestionável. Linguagens tradicionalmente não orientadas a objeto, por exemplo, Visual Basic ou Cobol, já apresentam versões que usufruem dessa técnica, ajudando a disseminar tal tecnologia para um público antes restrito a práticas consideradas ultrapassadas. Uma maneira comum de o sistema orientado a objetos resolver um problema é através de projeto de classes ou hierarquias de classes, definindo os relacionamentos corretos entre as instâncias destas e persistindo as informações ali armazenadas em tabelas num banco de dados relacional. Mover os dados do mundo orientado a objeto para o mundo relacional pode parecer uma tarefa trivial, mas na realidade é um antigo problema, que pode ser bastante complexo. O .Net Framework tornou este problema ainda mais complexo já que orientação a objetos é o conceito fundamental no código gerenciado. É muito fácil encontrarmos profissionais de informática com dúvidas do gênero “por onde começo o projeto de um sistema multicamadas, pela modelagem das classes ou pela modelagem das tabelas do banco de dados?”. Independentemente de onde você começar, com certeza precisará gastar um bom tempo fazendo o mapeamento de um modelo para outro. E qual o mapeamento adequado entre as classes e tabelas: uma classe para cada tabela ou várias tabelas para cada classe? Será que as regras de normalização de um banco de dados relacional devem ser mantidas?

Não seria interessante se existisse uma camada de software que encapsulasse essa complexidade de mapeamento de classes e tabelas e que possibilitasse ao programador mudar radicalmente o mapeamento, sem que o código cliente sofresse algum impacto? A Microsoft vem trabalhando continuamente para disponibilizar essa infra-estrutura para o desenvolvedor, e a linguagem de consulta para interagir com esta camada será a OPath.

OPath

OPath é o meio pelo qual você expressa critérios de seleção para a camada de persistência de objetos e como resultado recebe os objetos que satisfazem tal critério. Para os que conhecem a linguagem XPath, não será difícil aprender a OPath, pois ela baseia-se nos conceitos de navegação da linguagem XPath, já que as arvores semi-estruturadas XML são semelhantes aos grafos de objetos.

Veja um exemplo: imagine o seguinte conjunto de classes apresentado na Listagem 1 em C#. Suponha que você queira recuperar todos os clientes que possuem ordens de compra. Em OPath você escreve a seguinte expressão:


            Exists(Clientes.Compras)
        

Vamos restringir ainda mais a seleção para os clientes que possuem compras entre 10 e 20 de fevereiro.


            Exists(Clientes.Compras[DataCompra>='10/02/2004' and DataCompra < ='20/02/2004'])
                

Podemos restringir ainda mais os clientes para apenas aqueles clientes que compraram produtos com preço superior a 100 reais.


            Exists(Clientes.Compras[DataCompra>='10/02/2004' and DataCompra<='20/02/2004'].Items[Preco>100])
                

As três expressões são exemplos básicos que não exigiram nenhuma construção mais complexa. Para acessar a propriedade de um objeto, o desenvolvedor deve utilizar o operador '.', ou seja, para acessar a lista de compras dos clientes escreve-se a expressão Clientes.Compras. Uma vez selecionada a lista desejada, podemos adicionar critérios de seleção, conhecidos também como predicados, utilizando os colchetes. Todas as expressões dentro dos colchetes têm como escopo o objeto especificado à esquerda do colchete esquerdo. Quando escrevemos Clientes.Compras[DataCompra ='17/02/2004'], a propriedade DataCompra se refere ao objeto especificado à esquerda do colchete, neste caso, a lista de objetos do tipo OrdemCompra. Portanto são dois os conceitos essenciais que você precisa apreender para escrever expressões OPath; o primeiro consiste em como navegar a partir de um objeto para outro, utilizando o operador '.'; e o segundo em como descrever critérios de seleção para filtrar apenas os objetos desejados, utilizando os predicados dentro dos colchetes.

Agora vamos traduzir estas expressões OPath para a linguagem SQL. Veremos que os comandos SQL equivalentes não são tão simples assim. Como nosso modelo de classe é simples, adotaremos o mapeamento de um para um, conforme mostrado na Figura 1. Cada classe será armazenada em uma tabela.

Mapeamento da tabela
Figura 1. Mapeamento da tabela

O primeiro filtro pode ser traduzido para SQL como:


            Select Clientes.* From Clientes

            Where exists(

            select 1 from Compras

            Where Clientes.ClienteID=Compras.ClienteID)


                

Para o segundo filtro, temos:


            Select Clientes.* From Clientes

            Where exists(
            
              select 1 from Compras
            
              where Clientes.ClienteID=Compras.ClienteID
            
              and Compras.DataCompra between '10/02/2004'
            
              and '20/02/2004')
                

E, para o terceiro filtro, temos:


            Select Clientes.* From Clientes

            Where exists(   
            
              select 1 from Compras
            
              join Items on Compras.OrdemID = Items.OrdemID
            
              where Clientes.ClienteID=Compras.ClienteID
            
              and Compras.DataCompra between '10/02/2004'
            
              and '20/02/2004' and Item.Preco > 100)
                

Esses comandos SQL podem ser reescritos de forma semelhante a exposta. Observe o terceiro filtro e compare com a expressão OPath equivalente. A expressão OPath é bem mais simples, já que ela oculta a complexidade de fazer os joins entre as três tabelas envolvidas e coloca os critérios de seleção na posição correta. Cabe à camada de persistência de objetos traduzir as expressões OPath nos comandos SQL equivalentes (tanto semanticamente como da maneira mais otimizada possível), eliminando a necessidade de se escrever manualmente tais comandos SQL. Para traduzir uma expressão OPath, a camada de persistência necessita do mapeamento entre as classes e seus relacionamentos, e entre as tabelas e seus relacionamentos. O fato de esse mapeamento poder ser alterado durante o ciclo de desenvolvimento, sem nenhum ou praticamente nenhum impacto no código cliente, proporciona ao desenvolvedor a rapidez e agilidade necessárias para atender às constantes mudanças nos requisitos de um projeto.

Listagem 1. Classes da tabela

Public class Cliente

{

  Public string Nome;

  Public Nullable Endereco;

  Public Collection Compras;

}

Public class Endereco

{

  Public string Rua;

  Public string Cidade;

  Public string Estado;

  Public string Cep;

  Public string Pais;

}
 
Public class OrdemCompra

{

  Public DateTime DataCompra;

  Public Nullable EnderecoEnvio;

  Public Collection Items;

}

Public class ItemCompra

{

  Public string Produto;

  Public decimal Preco;

  Public int Quantidade; 

}
            

Conclusão

Este artigo apresentou os conceitos fundamentais da nova linguagem de consulta OPath, sua relação com outras linguagens (como SQL) e exemplos básicos de sua sintaxe. Saber escrever consultas em OPath é requisito básico para desfrutar dos benefícios do novo sistema de arquivos denominado WinFS, um dos pilares do próximo sistema operacional da Microsoft (codenome Longhorn). O cronograma do sistema operacional Longhorn prevê o lançamento da versão Beta ainda no ano 2004, e a versão final ao término do ano 2005.

Nota: OPath é o meio pelo qual você expressa critérios de seleção para a camada de persistência de objetos e, como resultado, recebe os objetos que satisfazem tal critério.
Revista MSDN Magazine Edição 5
Clique aqui para ler todos os artigos desta edição