Capítulo 4: Armazenamento
Introdução
Capítulo 1: o modelo de aplicativo "Longhorn"
Capítulo 2: Criando um aplicativo "Longhorn"
Capítulo 3: Controles e XAML
Capítulo 4: Armazenamento
Refatoração Brent
Wise Owl Consulting
Janeiro de 2004
ATUALIZAÇÃO: apesar do que pode ser declarado neste conteúdo, "WinFS" não é um recurso que virá com o Sistema Operacional Longhorn. No entanto, "WinFS" estará disponível na plataforma Windows em alguma data futura, razão pela qual este artigo continua a ser fornecido para suas informações.
Sumário
O que é o WinFS?
Modelo de programação do WinFS
Usando a API do WinFS e o SQL
Resumo
De certa forma, o computador pessoal é um nome inadequado. A maioria das pessoas não usa um computador pessoal para calcular. Eles usam um computador para se comunicar (por email ou mensagens instantâneas) e para armazenar e organizar seus dados pessoais (como email, documentos, imagens e música digital). Infelizmente, embora seu computador atualmente armazene esses dados muito bem, ele faz um trabalho relativamente ruim de permitir que você organize as informações para que você possa encontrá-los mais tarde.
A capacidade do disco vem crescendo cerca de 70% ao ano na última década. Atualmente, é possível comprar unidades com mais de 250 gigabytes (GB) de armazenamento. É provável que unidades de 500 GB fiquem disponíveis nos próximos anos e que muitos sistemas tenham mais de uma unidade de disco. Acabei de fazer um marcar rápido no computador no qual estou escrevendo este capítulo, e tenho 283.667 arquivos em 114.129 pastas em apenas 200 GB de espaço em disco. Quando eu esqueço exatamente onde coloquei um arquivo, pode levar um bom tempo para encontrá-lo novamente. Na pior das hipóteses, tenho que pesquisar todo o conteúdo de cada disco. Em alguns anos, as pessoas poderão armazenar milhões de arquivos, a maioria dos quais, se nada melhorar, nunca mais verão.
Uma das razões pelas quais as pessoas têm dificuldade em encontrar informações em seu computador é devido à capacidade limitada para o usuário organizar dados. O suporte atual do sistema de arquivos para pastas e arquivos funcionou bem originalmente porque era um paradigma familiar para a maioria das pessoas e o número de arquivos era relativamente pequeno. No entanto, isso não permite que você armazene facilmente uma imagem do seu colega bob jogando soft no piquenique da empresa de 2007 em um parque local e, posteriormente, encontre a imagem ao procurar documentos que:
- Mencionar Bob
- Envolver esportes
- Relacionar-se a eventos da empresa
- Pertencer ao parque ou sua área circundante
- Foram criados em 2007
A estrutura de pastas hierárquicas não funciona bem quando você deseja categorizar dados de várias maneiras. Portanto, temos um problema hoje em que temos muitas coisas para armazenar e nenhuma boa maneira de categorizá-lo. Além de categorizar informações, que muitas pessoas associam à anexação de um conjunto fixo de palavras-chave aos dados, as pessoas precisam relacionar dados. Por exemplo, talvez eu queira relacionar uma imagem com o piquenique da empresa, ou talvez eu queira relacionar uma foto com Bob, que também é membro de uma organização à qual doo tempo e esforço, como um contato.
Outro problema é que armazenamos o mesmo material em vários locais em vários formatos. Os desenvolvedores gastam muito tempo e esforço criando suas próprias abstrações de armazenamento exclusivas para informações diárias, como Pessoas, Locais, Horários e Eventos. Por exemplo, o Microsoft Outlook tem uma definição de um Contato. O Catálogo de Endereços do Microsoft Windows também tem sua própria definição de um contato. Cada aplicativo de mensagens instantâneas tem mais um. Cada aplicativo armazena sua definição de um contato em um silo exclusivo e isolado de informações.
Há uma série de problemas com as abordagens atuais para o armazenamento de dados, incluindo o seguinte:
- Os desenvolvedores reinventam as abstrações de dados básicas repetidamente.
- Vários aplicativos não podem compartilhar facilmente dados comuns.
- As mesmas informações residem em vários locais.
- O usuário insere repetidamente as mesmas informações.
- Cópias separadas de dados se tornam não sincronizadas.
- Não há notificações de alteração de dados.
O que é o WinFS?
O WinFS é o novo sistema de armazenamento no Longhorn. Ele melhora a plataforma Microsoft Windows de três maneiras. Primeiro, ele permite categorizar suas informações de várias maneiras e relacionar um item de informações a outro. Em segundo lugar, ele fornece um formato de armazenamento comum para informações coletadas diariamente, como informações que lidam com pessoas, locais, imagens e muito mais. Em terceiro lugar, ele promove o compartilhamento de dados de informações comuns em vários aplicativos de vários fornecedores.
O WinFS é uma plataforma de armazenamento
O WinFS é uma plataforma de armazenamento ativa para organizar, pesquisar e compartilhar todos os tipos de informações. Essa plataforma define um modelo de dados avançado que permite usar e definir tipos de dados avançados que a plataforma de armazenamento pode usar. O WinFS contém vários esquemas que descrevem entidades reais, como Imagens, Documentos, Pessoas, Locais, Eventos, Tarefas e Mensagens. Essas entidades podem ser bastante complexas. Por exemplo, uma pessoa pode ter vários nomes, vários endereços físicos e de email, um local atual e muito mais.
Os ISVs (fornecedores independentes de software) também podem definir seus próprios novos tipos de dados e fornecer seu esquema ao WinFS. Ao permitir que o WinFS gerencie problemas complexos de armazenamento, um ISV pode se concentrar no desenvolvimento de sua lógica de aplicativo exclusiva e aproveitar as instalações de armazenamento mais avançadas do WinFS para seus dados personalizados e cotidianos.
O WinFS contém um mecanismo relacional que permite localizar instâncias de tipos de armazenamento usando consultas relacionais avançadas. O WinFS permite combinar essas entidades de armazenamento de maneiras significativas usando relações. Um contato pode ser um membro do grupo Funcionários de uma Organização enquanto, simultaneamente, um membro do grupo Doméstico para um endereço específico. Os ISVs ganham automaticamente a capacidade de pesquisar, replicar, proteger e estabelecer relações entre seus tipos de dados exclusivos, bem como entre os tipos de dados predefinidos do Windows.
Essa estrutura permite que o usuário faça perguntas ao sistema e peça a ele para localizar informações em vez de pedir ao sistema para pesquisar pastas individualmente. Por exemplo, você pode pedir ao WinFS para encontrar todas as mensagens de email de pessoas em sua lista de parceiros de mensagens instantâneas para as quais você não tem um número de telefone. Usando consultas relacionais, você pode encontrar todos os membros de uma Família para um funcionário específico com um aniversário no mês atual.
O WinFS também dá suporte a vários modelos de programação flexíveis que permitem escolher a API (interface de programação de aplicativo) apropriada para a tarefa. Você pode acessar o repositório usando consultas relacionais tradicionais usando SQL (linguagem de consulta estruturada). Como alternativa, você pode usar classes e objetos .NET para acessar o armazenamento de dados. Você também pode usar APIs baseadas em XML no armazenamento de dados. O WinFS também dá suporte ao acesso a dados por meio da API tradicional do sistema de arquivos Do Microsoft Win32. Você pode até mesmo misturar e corresponder, ou seja, usar várias APIs para uma única tarefa. No entanto, para a maioria das finalidades, os desenvolvedores usarão as APIs de classe gerenciada para alterar os dados no repositório WinFS. Geralmente, será muito mais complexo fazer uma atualização usando instruções SQL brutas em comparação com o uso das APIs de objeto.
Além disso, o WinFS fornece um conjunto de serviços de dados para monitorar, gerenciar e manipular seus dados. Você pode se registrar para receber eventos quando determinados itens de dados forem alterados. Você pode agendar o WinFS para replicar seus dados para outros sistemas.
O WinFS é um sistema de arquivos
Para dados tradicionais baseados em arquivo, como documentos de texto, faixas de áudio e clipes de vídeo, o WinFS é o novo sistema de arquivos do Windows. Normalmente, você armazenará os dados main de um arquivo, o fluxo de arquivos, como um arquivo em um volume NTFS. No entanto, sempre que você chama uma API que altera ou adiciona itens com partes de fluxo de arquivo NTFS, o WinFS extrai os metadados do fluxo e adiciona os metadados ao repositório WinFS. Esses metadados descrevem informações sobre o fluxo, como seu caminho, além de qualquer informação que o WinFS possa extrair do fluxo. Dependendo do conteúdo do arquivo, esses metadados podem ser o autor (de um documento), o gênero (de um arquivo de áudio), palavras-chave (de um arquivo PDF) e muito mais. O WinFS sincroniza o fluxo de arquivos residente do NTFS e os metadados residentes do WinFS. Novos aplicativos Longhorn também podem optar por armazenar seus fluxos de arquivos diretamente no WinFS. Os fluxos de arquivos podem ser acessados usando a API do sistema de arquivos Win32 existente ou a nova API do WinFS.
O WinFS não é apenas um sistema de arquivos
Um sistema de arquivos gerencia arquivos e pastas. Embora o WinFS gerencie arquivos e pastas, ele também gerencia todos os tipos de dados não baseados em arquivo, como contatos pessoais, calendários de eventos, tarefas e mensagens de email. Os dados do WinFS podem ser estruturados, semiestruturados ou não estruturados. Os dados estruturados incluem um esquema que define adicionalmente para que servem os dados e como você deve usá-los. Como o WinFS é, em parte, um sistema relacional, ele impõe a integridade dos dados em relação à semântica, transações e restrições.
O WinFS também não é apenas um sistema relacional. Ele dá suporte ao armazenamento hierárquico e ao armazenamento relacional. Ele dá suporte ao retorno de dados como tipos estruturados e como objetos , tipos mais comportamento. Você pode considerar o WinFS um sistema de armazenamento de dados hierárquico, relacional e orientado a objetos, embora ele realmente contenha determinados aspectos de cada um desses sistemas de armazenamento tradicionais. O WinFS vai além do sistema de arquivos tradicional e do sistema de banco de dados relacional. É o repositório para todos os tipos de dados na plataforma mais recente do Windows.
WinFS e NTFS
Você pode armazenar um arquivo no sistema de arquivos NTFS tradicional ou no novo armazenamento de dados WinFS, assim como pode armazenar itens no FAT32 ou no CD-ROMs ou no NTFS hoje. Normalmente, um arquivo armazenado no NTFS não está visível no WinFS. Os aplicativos Longhorn que usam as novas APIs do WinFS podem acessar dados armazenados no WinFS ou no NTFS. Além disso, os aplicativos Longhorn podem continuar a usar a API Win32 para acessar dados armazenados no sistema de arquivos NTFS.
Promoção de Arquivos
Os arquivos estão no WinFS ou não. Qualquer item que tenha uma parte de fluxo de arquivos pode participar da promoção/rebaixamento, que geralmente chamamos de tratamento de metadados. Quando o WinFS promove um arquivo, ele extrai os metadados do conteúdo do arquivo NTFS conhecido e adiciona os metadados ao armazenamento de dados do WinFS. O fluxo de dados real do arquivo permanece no sistema de arquivos NTFS. Em seguida, você pode consultar o WinFS sobre os metadados como se o arquivo residisse nativamente no WinFS. O WinFS também detecta alterações no arquivo NTFS e atualiza os metadados dentro do armazenamento de dados do WinFS conforme necessário.
Importação e exportação de arquivos
Você também pode importar um arquivo para o WinFS do NTFS e exportar um arquivo do WinFS para o NTFS. Importar e exportar um arquivo move o conteúdo do arquivo e os metadados. Depois de importar ou exportar, o novo arquivo é completamente independente do arquivo original.
Modelo de programação do WinFS
O modelo de programação do WinFS inclui acesso a dados, manipulação de dados, extensibilidade de classe de dados do WinFS, sincronização de dados, notificações de alteração de dados e priorização de eventos. O acesso a dados e a manipulação de dados permitem que você crie, recupere, atualize e exclua dados armazenados no WinFS e exerça comportamentos específicos do domínio. A extensibilidade da classe de dados permite estender esquemas WinFS com campos personalizados e tipos personalizados. A sincronização de dados permite sincronizar dados entre repositórios WinFS e entre um WinFS e um repositório não WinFS.
A parte superior da hierarquia do modelo de dados do WinFS é um serviço WinFS, que é simplesmente uma instância do WinFS. Um nível na hierarquia do serviço é um volume. Um volume é o maior contêiner autônomo de itens. Cada instância do WinFS contém um ou mais volumes. Dentro de um volume há itens.
O WinFS apresenta o item como a nova unidade de consistência e operação, em vez do arquivo. O sistema de armazenamento armazena itens. Você tem uma grande capacidade de consulta em relação aos itens. Um item é efetivamente um tipo base do sistema de armazenamento. Portanto, um item tem um conjunto de atributos de dados e fornece uma funcionalidade básica de consulta.
Pessoas normalmente organizam dados no mundo real de acordo com algum sistema que faz sentido em um determinado domínio. Todos esses sistemas particionam dados em grupos nomeados. O WinFS modela essa noção com o conceito de uma pasta. Uma pasta é um tipo especial de item. Há dois tipos de pastas: pastas de contenção e pastas virtuais.
Uma pasta de contenção é um item que contém links para outros itens e modela o conceito comum de uma pasta do sistema de arquivos. Existe um item desde que pelo menos um link de retenção faça referência a ele. Observe que uma pasta de contenção não contém diretamente os itens logicamente presentes na pasta, mas contém links para esses itens. Isso permite que várias pastas de contenção contenham o mesmo item.
Uma pasta virtual é uma coleção dinâmica de itens. É um conjunto nomeado de itens. Você pode enumerar o conjunto explicitamente ou especificar uma consulta que retorna os membros do conjunto. Uma pasta virtual especificada por uma consulta é bastante interessante. Quando você adiciona um novo item ao repositório que atende aos critérios da consulta de uma pasta virtual, o novo item é automaticamente um membro da pasta virtual. Uma pasta virtual é um item em si. Conceitualmente, ele representa um conjunto de links não retidos para itens, como você pode ver na Figura 4-1.
Figura 4-1. A hierarquia do modelo de dados do WinFS
Às vezes, você precisa modelar uma noção altamente restrita de contenção, por exemplo, um documento do Microsoft Word inserido em uma mensagem de email é, de certa forma, associado mais firmemente ao contêiner do que, por exemplo, um arquivo contido em uma pasta. O WinFS expressa essa noção usando itens inseridos. Um item inserido é um tipo especial de link dentro de um item (chamado Link Inserido) que faz referência a outro item. O item referenciado pode ser associado ou manipulado somente dentro do contexto do item que contém.
Por fim, o WinFS fornece a noção de categorias como uma maneira de classificar itens. Você pode associar uma ou mais categorias a cada item no WinFS. O WinFS, na verdade, marca o nome da categoria no item. Em seguida, você pode especificar o nome da categoria nas pesquisas. O modelo de dados do WinFS permite a definição de uma hierarquia de categorias, permitindo assim uma classificação de dados semelhante a uma árvore.
Organizando informações
Todos esses recursos juntos permitem cinco maneiras de organizar suas informações no WinFS:
- Organização hierárquica baseada em pastas. Com essa abordagem, você ainda tem a estrutura tradicional da organização de itens e pasta hierárquica. Todos os itens em um armazenamento de dados do WinFS devem residir em um contêiner e um desses tipos de contêiner é uma pasta.
- Organização baseada em tipo. Um item é sempre de um tipo específico. Por exemplo, você tem itens person, itens de foto, itens da organização e muitos outros tipos disponíveis. Você pode até mesmo criar novos tipos e armazená-los no armazenamento de dados do WinFS.
- Organização baseada em propriedade de item. Você pode exibir itens que têm uma ou mais propriedades definidas para valores especificados. Essa é, na verdade, uma exibição de pasta virtual com uma consulta que retorna os itens com o valor especificado para as propriedades especificadas.
- Organização baseada em relacionamento. Você pode recuperar itens com base na relação deles com outros itens, por exemplo, uma Pessoa pode ser membro de uma Organização e pode ser organizada ou pesquisada em termos dessa relação.
- Organização baseada em categoria. Você pode criar e associar qualquer número de palavras-chave definidas pelo usuário a um item. Posteriormente, você pode recuperar os itens que têm um valor específico para um palavra-chave associado. No entanto, você não poderá criar taxonomias de categorização, portanto, essa técnica de organização não é tão poderosa quanto as abordagens anteriores.
WinFS APIs
O WinFS fornece três APIs de acesso a dados: a API do WinFS gerenciada, a API ADO.NET e a API Win32. A API do WinFS é uma API de "alto nível" fortemente tipada. ADO.NET fornece uma API de nível inferior para trabalhar com dados como XML ou como tabelas ou linhas. Usando ADO.NET, você pode acessar dados armazenados no WinFS usando Transact-Structured T-SQL (Linguagem de Consulta) e, quando desejar, recuperar dados em XML usando a funcionalidade FOR XML do T-SQL. A API Win32 permite acesso aos arquivos e pastas armazenados no WinFS.
Talvez você prefira usar vários padrões de acesso para resolver um problema. Por exemplo, você pode emitir uma consulta T-SQL que retorna um conjunto de contatos como objetos gerenciados do tipo Contato do WinFS. Independentemente da API que você usa, cada API manipula dados no repositório WinFS usando T-SQL.
Em muitos casos, você preferirá usar a API do WinFS gerenciada. Essas classes .NET Framework executam automaticamente o mapeamento de relação de objeto necessário para traduzir entre constructos de programação orientados a objetos e executam o T-SQL necessário para obter o acesso a dados do WinFS.
Usando as classes WinFS gerenciadas
As classes gerenciadas do WinFS residem no System.Storage
namespace e nos namespaces aninhados. Muitos aplicativos também usarão definições de tipo WinFS do System.Storage.Core
namespace. Além disso, você pode usar tipos de namespaces mais especializados. Por exemplo, as classes gerenciadas que manipulam a definição do sistema de um Contato residem no System.Storage.Contact
namespace. Para simplificar, todos os exemplos de código neste capítulo usarão o seguinte conjunto de using
declarações:
using System.Storage;
using System.Storage.Core;
using System.Storage.Contact;
ItemContext
O repositório WinFS consiste em itens organizados em pastas e categorizados. A primeira etapa para trabalhar com o WinFS é identificar o conjunto de itens com os quais você deseja trabalhar. Chamamos essa associação de processo e o conjunto de itens pode ser qualquer um dos seguintes:
- Um volume inteiro (também conhecido como pasta raiz)
- Um subconjunto identificável de itens em um determinado volume, por exemplo, uma pasta de contenção específica ou uma pasta virtual
- Um item individual
- Um compartilhamento WinFS (que identifica um volume, uma pasta, uma pasta virtual ou um item individual)
Para associar a um conjunto de itens, você cria um System.Storage.ItemContext
objeto e o conecta a um armazenamento de dados do WinFS. Use o método auxiliar estático System.Storage.ItemContext.Open
para criar um ItemContext
objeto .
O código a seguir cria um ItemContext
que se conecta ao volume winFS local padrão. O padrão é o compartilhamento \\local-computer-name\DefaultStore:
System.Storage.ItemContext ctx = System.Storage.ItemContext.Open ();
§
ctx.Close();
Como alternativa, você pode passar uma cadeia de caracteres para o construtor para conectar o contexto do item a um repositório WinFS específico. O código a seguir cria um contexto de item conectado a um compartilhamento WinFS identificado pelo compartilhamento \\machine\Legal Documents:
ItemContext ctx = null;
try {
ctx = ItemContext.Open (@"\machine\Legal Documents");
§
}
finally {
if (ctx != null) ctx.Dispose();
}
Feche ou descarte o objeto de contexto assim que terminar de usá-lo, independentemente das exceções. Um ItemContext
usa recursos não gerenciados significativos, como uma conexão com o repositório, que você deve liberar em tempo hábil. Para tornar os contextos de fechamento o mais convenientes possível, a ItemContext
classe implementa a IDisposable
interface . Portanto, você pode usar a instrução C# using
conforme mostrado no exemplo a seguir para liberar esses recursos:
using (ItemContext ctx = ItemContext.Open (@"D:\MyStore")) {
§
}
Armazenando um novo item em um armazenamento de dados do WinFS
Cada item em um armazenamento de dados do WinFS deve ser membro de uma pasta do repositório. Você obtém a raiz da hierarquia de pastas chamando o método System.Storage.Folder.GetRootFolder
estático extremamente bem nomeado . No entanto, também há vários contêineres definidos pelo sistema para armazenar dados específicos do aplicativo. Geralmente, você usa um dos métodos estáticos na UserDataFolder
classe para recuperar uma pasta na qual você coloca novos itens.
Obtendo uma pasta
No exemplo a seguir, encontrarei a pasta Contatos Pessoais do usuário atual se ela existir e criá-la quando ela não existir. Observe que esse é um exemplo um pouco inventado— o sistema cria automaticamente a pasta Contatos Pessoais de um usuário se ela não existir quando o usuário faz logon pela primeira vez em um sistema — mas me dá a chance de mostrar como criar uma pasta esperada quando ela não existir.
ItemContext ctx = ItemContext.Open ();
WellKnownFolder contactsFolder =
UserDataFolder.FindUsersWellKnownFolderWithType (ctx,
GeneralCategories.PersonalContactsFolder);
if (contactsFolder == null) {
//create the Personal Contacts folder
Folder userDataFolder = UserDataFolder.FindMyUserDataFolder (ctx);
WellKnownFolder subFolder = new WellKnownFolder (ctx);
CategoryRef category = new CategoryRef (ctx,
GeneralCategories.PersonalContactsFolder);
// Associate the PersonalContactsFolder category to the folder
subFolder.FolderType = category;
userDataFolder.AddMember (subFolder);
ctx.Update();
}
O código anterior faz várias coisas interessantes. Primeiro, tento localizar uma pasta existente contida na hierarquia de pastas de dados pessoais do usuário. Não estou procurando a pasta por um nome conhecido. Em vez disso, estou localizando a pasta dentro da árvore de dados pessoal do usuário que foi associada anteriormente à categoria PersonalContactsFolder
conhecida . O shell exibe essa pasta quando você seleciona Meus Contatos.
Normalmente, essa pasta já existe, mas quando não existe, recuperei a pasta raiz da hierarquia de dados do usuário. Eu crio um novo item, do tipo WellKnownFolder
e, em seguida, crio uma referência a uma categoria conhecida, a PersonalContactsFolder
categoria . Em seguida, defina o tipo da nova pasta para o PersonalContactsFolder
tipo de categoria e, por fim, adiciono a nova pasta à pasta que contém a pasta raiz de dados pessoais do usuário. O WinFS não salva nenhuma alteração no armazenamento de dados até que você chame Update
no contexto do item (o que eu esqueço regularmente de fazer).
É claro que essa é a maneira detalhada de encontrar a pasta Contatos Pessoais. Eu queria mostrar como as coisas funcionam. Normalmente, eu usaria o código a seguir. O FindMyPersonalContactsFolder
método localiza a pasta existente.
WellKnownFolder userDataFolder =
UserDataFolder.FindMyPersonalContactsFolder (ctx);
Criando um novo item
Como agora tenho a pasta Contatos Pessoais, parece apropriado criar um novo contato na pasta. No exemplo a seguir, criarei vários contatos de Pessoa e os adicionarei à pasta :
Person[] CreateFriends (ItemContext ctx) {
string[] GivenNames = { "Monica", "Rachel", "Chandler",
"Joey", "Phoebe", "Ross"};
string[] SurNames = { "Uchra", "Emerald", "Ranier",
"Fibonacci", "Smorgasbord", "Uchra"};
Person[] Friends = new Person [GivenNames.Length];
for (int index = 0; index < GivenNames.Length; index++) {
string linkName = GivenNames[index] + " " + SurNames[index];
Person p = Person.CreatePersonalContact (ctx, linkName);
Friends[index] = p;
p.DisplayName = linkName;
FullName fn = p.GetPrimaryName ();
fn.GivenName = GivenNames[index];
fn.Surname = SurNames[index];
}
ctx.Update ();
}
O código anterior usa o método estático Person.CreatePersonalContact
. Este método
- Cria um novo item Person no contexto de item especificado
- Cria uma nova
FolderMember
relação com o nome especificado que faz referência à Pessoa - Adiciona a
FolderMember
relação àPersonalContactsFolder
coleção doRelationship
Posteriormente, atualizei as DisplayName
propriedades , GivenName
e Surname
do item Person. Como sempre, eu chamo Update
no contexto do item para salvar as alterações no armazenamento de dados.
Vamos examinar mais de perto o CreatePersonalContact
método . É equivalente ao seguinte:
// Find the PersonalContacts folder
WellKnownFolder contactsFolder =
UserDataFolder.FindUsersWellKnownFolderWithType (ctx,
GeneralCategories.PersonalContactsFolder);
// Create a new Person item
Person p = new Person (ctx);
// Need a folder relationship that references the new Person
FolderMember fm = new FolderMember (p, linkName);
folder.Relationships.Add (fm);
ctx.Update ();
Itens de relação
O WinFS define um modelo de dados de relação que permite relacionar itens entre si. Ao definir o esquema para um tipo de dados, você pode definir zero ou mais relações como parte do esquema. Por exemplo, o esquema Folder define a relação FolderMember . O esquema organização define a Employee
relação. Para cada relação definida, há uma classe que representa a própria relação. Essa classe é derivada da Relationship
classe e contém membros específicos do tipo de relação. Há também uma classe de coleção "virtual" fortemente tipada. Essa classe é derivada de VirtualRelationshipCollection
e permite que instâncias de relação sejam criadas e excluídas.
Uma relação relaciona um item de origem a um item de destino. No exemplo anterior, a pasta Contatos Pessoais era o item de origem e o item Pessoa era o item de destino. A FolderMember
relação basicamente indica que o item Pessoa está relacionado à pasta Contatos Pessoais como um membro da pasta.
Quando você define uma relação, define se a relação mantém o item de destino existente, uma relação de retenção, ou não mantém o item de destino existente, uma relação de referência. Quando você cria uma relação de retenção com um item de destino, o WinFS incrementa uma contagem de referência no item de destino. Quando o WinFS exclui uma relação de retenção, ele diminui a contagem de referência no item de destino. Um item não existe mais no repositório quando sua contagem de referência atinge zero. O WinFS nunca altera a contagem de referência do destino quando você cria ou destrói uma relação de referência com o destino. Portanto, o item de destino pode desaparecer do repositório quando sua contagem de referência atingir zero e a relação pode se referir a um item não mais existente.
O WinFS define a FolderMember
relação como uma relação de retenção. A maioria das outras classes de relação são relações de referência.
Itens de Pasta
Agora que você sabe sobre os itens do Link, posso refinar minha descrição de Itens de pasta. Uma Pasta é um item WinFS que tem uma coleção de itens de Link. O destino de cada item link na coleção é um membro da pasta. A Folder.Members
propriedade representa essa coleção de links.
Observe que isso dá a uma pasta WinFS uma flexibilidade muito maior do que as pastas tradicionais do sistema de arquivos. Os membros de uma pasta podem ser itens de arquivo e não arquivo. Vários links para um item específico podem residir em muitas pastas simultaneamente. Em outras palavras, várias pastas podem conter o mesmo item.
Outros tipos de item
Em geral, você cria outros tipos de item no repositório WinFS como fez nos exemplos anteriores. Cada tipo ocasionalmente tem seu próprio padrão de uso especial. Por exemplo, podemos ter organizações como membros de nossa pasta Contatos Pessoais, portanto, vamos criar uma:
Organization cp = FindOrCreateOrganization (ctx, "Main Benefit");
§
Organization FindOrCreateOrganization (ItemContext ctx, string orgName) {
Organization o =
Organization.FindOne (ctx, "DisplayName='" + orgName + "'");
if (o == null) {
Folder Pcf = UserDataFolder.FindMyPersonalContactsFolder (ctx);
o = new Organization (ctx);
o.DisplayName = orgName;
Folder pcf = UserDataFolder.FindMyPersonalContactsFolder (ctx);
pcf.AddMember (o, o.DisplayName.ToString ());
ctx.Update ();
}
return o;
}
Agora vamos adicionar um funcionário a essa organização:
enum Names { Monica, Rachel, Chandler, Joey, Phoebe, Ross }
§
Person[] Friends = CreateFriends (ctx);
Organization cp = FindOrCreateOrganization (ctx, "Main Benefit");
AddEmployeeToOrganization (ctx, Friends [(int)Names.Rachel],
cp);
§
void AddEmployeeToOrganization (ItemContext ctx, Person p, Organization o) {
EmployeeData ed = new EmployeeData (ctx);
ed.Name = p.DisplayName;
ed.Target_Key = p.ItemID_Key;
o.Employees.Add (ed);
ctx.Update ();
}
Da mesma forma, podemos criar famílias em nossas pastas contatos pessoais. Observe que uma família não implica uma família. Uma casa pode ser um grupo de colegas de quarto. O WinFS tem esquema adicional para famílias, mas vou deixar isso como um exercício para o leitor.
CreateHousehold (ctx, Friends [(int) Names.Chandler],
Friends [(int) Names.Joey]);
CreateHousehold (ctx, Friends [(int) Names.Monica],
Friends [(int) Names.Rachel]);
§
void CreateHousehold (ItemContext ctx, Person p1, Person p2) {
Household h = new Household (ctx);
h.DisplayName = p1.GetPrimaryName().GivenName + " and " +
p2.GetPrimaryName().GivenName + " household";
Folder pcf = UserDataFolder.FindMyPersonalContactsFolder (ctx);
pcf.AddMember (h, h.DisplayName.ToString ());
// Add first person to the household
HouseholdMemberData hhmd = new HouseholdMemberData (ctx);
hhmd.Name = p1.DisplayName;
hhmd.Target_Key = p1.ItemID_Key;
h.HouseholdMembers.Add (hhmd);
// Add second person to the household
hhmd = new HouseholdMemberData (ctx);
hhmd.Name = p2.DisplayName;
hhmd.Target_Key = p2.ItemID_Key;
h.HouseholdMembers.Add (hhmd);
}
O exemplo anterior usa um conceito que ainda não discuti. Observe o uso da ItemID_Key
propriedade nesta linha de código:
hhmd.Target_Key = p1.ItemID_Key;
Basicamente, o ItemID_Key
valor é outra maneira de referenciar um item no repositório WinFS, portanto, vamos examinar as maneiras de encontrar itens no repositório.
Como localizar itens
É claro que não faz muito bem colocar itens em um armazenamento de dados se você não conseguir encontrá-los facilmente. A ItemContext
classe contém métodos de instância que você pode usar para recuperar itens em um armazenamento de dados do WinFS. Especifique que tipo de item localizar e quaisquer restrições especiais que os itens retornados devem atender. Além disso, cada classe de item, por exemplo, Person
, File
, Folder
e assim por diante, também contém métodos estáticos que permitem encontrar itens desse tipo específico.
O FindAll
método retorna um ou mais itens que correspondem aos critérios especificados. O ItemContext.FindAll
método de instância exige que você especifique o tipo dos itens a serem localizados. Além disso, opcionalmente, você pode especificar critérios de pesquisa para restringir o escopo da pesquisa. Por exemplo, o código a seguir localiza todos os itens person que têm uma DisplayName
propriedade cujo valor começa com "Brent".
FindResult res = ctx.FindAll (typeof(Person), "DisplayName='Brent%'");
foreach (Person p in res) {
// Use the Person item somehow
}
Como alternativa, eu poderia usar o método estático FindAll
da Person
classe como este:
FindResult res = Person.FindAll (ctx, "DisplayName='Brent%'");
foreach (Person p in res) {
// Use the Person item somehow
}
Em ambos os exemplos, o FindAll
método sempre retorna uma coleção dos itens que correspondem ao tipo e aos critérios especificados. Essa coleção pode não conter itens, mas você não recebe uma referência nula para o FindResult
. Portanto, sempre itere sobre a coleção para obter os itens encontrados.
Quando você souber que apenas um único item corresponderá ao tipo solicitado e aos critérios de filtro especificados, você poderá usar o FindOne
método . No entanto, tenha cuidado: o FindOne
método gera uma exceção quando encontra mais de um item que corresponde à sua solicitação.
Person p = Person.FindOne (ctx, "DisplayName='Brent Rector'");
O segundo parâmetro de cadeia de caracteres é uma expressão de filtro que permite especificar restrições adicionais que os itens retornados devem satisfazer. O formato básico da expressão de filtro é uma cadeia de caracteres no formato "<propertyName> <operator> <propertyValue>
".
O WinFS chama a expressão de expressão OPath
. A sintaxe é semelhante, embora não idêntica, à XPath
sintaxe de expressão usada para identificar itens em um documento XML. Esse fragmento de código retorna todos os itens de arquivo para arquivos com uma extensão de arquivo "doc" ou "txt":
FindResult Files = File.FindAll (ctx, "Extension='doc' || Extension='txt'");
Essas expressões podem ser bastante complexas. Por exemplo, a instrução a seguir retorna todos os itens person que representam funcionários de um empregador com o DisplayName
de "Benefício Principal":
string pattern = "Source(EmployeeOf).DisplayName='Main Benefit'";
FindResult result = Person.FindAll (ctx, pattern);
Aqui está outro. Quero os itens de Pessoa em que o Sobrenome não é "Ranier" e os endereços de email não terminem com ".edu".
string filter = "PersonalNames[Surname!='Ranier'] &&
!(PersonalEmailAddresses[Address like '%.edu'])");
FindResult result = Person.FindAll (ctx, filter);
Identificando um item específico
Com frequência, você precisa criar referências a itens no repositório do WinFS. Eventualmente, você usa essas referências para localizar o item apropriado. Anteriormente neste capítulo, mostrei como usar um link para fazer referência a um item. Os links usam uma identidade amigável baseada em cadeia de caracteres para a referência, e esse nome de cadeia de caracteres deve ser exclusivo dentro da pasta que contém o link. Em outras palavras, você precisa da pasta e de um de seus links contidos para identificar o item referenciado.
No entanto, você pode criar vários links com o mesmo nome de cadeia de caracteres amigável, desde que adicione os links a pastas diferentes para que todos os nomes dentro de uma única pasta permaneçam exclusivos. Observe que esses vários links com o mesmo nome de texto amigável não precisam fazer referência ao mesmo item de destino. Eles poderiam, mas não precisam.
Nesses casos, a pesquisa de todos os links com um nome de texto amigável específico (usando FindAll
, por exemplo) retornará vários resultados. Em seguida, você precisará examinar a origem de cada link para determinar a pasta que contém e determinar qual link faz referência ao item desejado.
Precisamos de uma maneira de fazer referência a qualquer item arbitrário no repositório, por exemplo, suponha que eu queira o 3.287º item na loja. Felizmente, você pode fazer exatamente isso.
Localizando um item por ItemID_Key valor
O WinFS atribui a cada item recém-criado um número de identificação baseado em GUID, conhecido como sua ItemID_Key
propriedade. Na prática, é altamente provável que um ItemID_Key
valor seja exclusivo em todos os volumes do WinFS; no entanto, o WinFS ainda trata esse identificador como se fosse exclusivo somente dentro de um volume. Você pode usar esse valor exclusivo do volume para identificar qualquer item em um volume do WinFS.
Item GetItem (ItemContext ctx, SqlBinary itemID_Key) {
// Convert itemID_Key to a string for use in the OPath filter
string hexItemID_Key = BitConverter.ToString (itemID_Key.Value);
hexItemID_Key = "'0x" + hexItemID_Key.Replace ("-", String.Empty) + "'";
// Build an opath filter expression.
string query = "ItemID_Key=" + hexItemID_Key;
return Item.FindOne (ctx, query);
}
Recursos comuns
A API do WinFS fornece vários recursos em todo o espectro de classes de dados. Esses recursos são
- Assíncrona
- Transactions
- Notificações
- Suporte a blob/fluxo
- Cursor e paginação
Assíncrona
A API do WinFS permite que você execute consultas de forma assíncrona. A API do WinFS usa os padrões de modelo de programação assíncrona padrão do .NET.
Transactions
O repositório WinFS é um repositório transacional. O WinFS, portanto, permite que você faça atualizações transacionais no repositório usando os BeginTransaction
métodos , CommitTransaction
e AbortTransaction
no ItemContext
objeto , conforme mostrado no exemplo a seguir:
using (ItemContext ctx = ItemContext.Open()) {
using (Transaction t = ctx.BeingTransaction()) {
Person p = Person.FindOne (ctx,
"PersonalNames[GivenName='Chandler' And SurName='Bing']" );
Household h = Household.FindOne (ctx,
"DisplayName = 'Chandler and Joey Household'");
p.PersonalEAddresses.Add (new TelephoneNumber ("202", "555-1234"));
p.Save ();
h.Members.Add (p);
h.Save ();
t.Commit ();
}
}
Notificações
O Serviço de Notificação do WinFS usa os conceitos de assinaturas de curto e longo prazo. Uma assinatura de curto prazo dura até que um aplicativo cancele a assinatura ou o aplicativo seja encerrado. Uma assinatura de longo prazo sobrevive às reinicializações do aplicativo. Os observadores de API do WinFS são um conjunto de classes que permitem que os aplicativos sejam notificados seletivamente sobre as alterações no armazenamento do WinFS e forneçam informações de estado que podem ser persistidas pelo aplicativo para dar suporte a cenários de suspensão/retomada.
A Watcher
classe pode notificar sua aplicação de alterações em diferentes aspectos de objetos WinFS, incluindo o seguinte:
- Alterações de item
- Alterações de item inserido
- Alterações de extensão de item
- Alterações de relação
Quando um observador gera um evento, ele envia dados de estado do observador com a notificação de evento. Seu aplicativo pode armazenar esses dados de estado para recuperação posterior. Posteriormente, você pode usar esses dados de estado do observador para indicar ao WinFS que deseja receber eventos para todas as alterações que ocorreram após a geração do estado.
O modelo de programação do observador também permite que qualquer combinação de eventos adicionados, modificados e removidos seja desabilitada. Ele também pode ser configurado para gerar um evento inicial que simula a adição de todos os itens existentes, extensões de item, relações e assim por diante.
O design do inspetor do WinFS é dividido nas classes descritas na tabela a seguir.
Classe | Finalidade/descrição |
---|---|
WatcherOptions |
Classe para especificar opções iniciais de escopo e granularidade para StoreWatcher |
StoreWatcher |
A classe quintessencial para assistir a itens do WinFS, itens inseridos, extensões de item e relações |
WatcherState |
Objeto opaco que pode ser usado para inicializar um StoreWatcher |
ChangedEventHandler |
Classe que define o manipulador de eventos a ser chamado por StoreWatcher |
ChangedEventArgs |
Classe passada como argumento para ChangedEventHandler |
ItemChangeDetail |
Classe base que fornece detalhes de alteração granular para eventos de item |
ItemExtensionChangeDetail |
Classe derivada de ItemChangeDetail que fornece detalhes de alteração adicionais específicos para eventos de extensão de item |
RelationshipChangeDetail |
Classe derivada de ItemChangeDetail que fornece detalhes de alteração adicionais específicos para eventos de relação |
Use a StoreWatcher
classe para criar um observador para algum item no repositório do WinFS. A StoreWatcher
instância gerará eventos quando o item especificado for alterado. Você pode especificar o tipo de item e hierarquia a watch. Por padrão, um observador
- Não gera um evento inicial para estabelecer o estado atual
- Observa o item e a hierarquia (incluindo filhos imediatos) para quaisquer alterações
- Gera eventos de adição, remoção e modificação neste item ou em qualquer filho em toda a hierarquia
- Gera eventos de adição, remoção e modificação para extensões de item neste item ou qualquer filho em toda a hierarquia
- Gera eventos de adição, remoção e modificação para relações nas quais este item ou qualquer filho em toda a hierarquia é a origem da relação
Como, por padrão, um observador observa as alterações no item especificado e seus descendentes, talvez você queira especificar WatchItemOnly
como a opção do observador. O exemplo a seguir observa as alterações somente no item Pessoa localizado:
Person p = Person.FindOne (ctx,
"PersonalNames[GivenName='Rachel' and Surname='Emerald'");
StoreWatcher w = new StoreWatcher ( p, WatcherOptions.WatchItemOnly );
Uma Pasta é apenas mais um item do WinFS. Você watch alterações em uma Pasta da mesma maneira que faz para uma Pessoa:
Folder f = · · ·
StoreWatcher w = new StoreWatcher (f, <WatcherOptions>);
Você também pode watch alterações em uma relação especificada de um item:
Person p = · · ·
StoreWatcher w = new StoreWatcher (p, typeof(HouseholdMember),
<WatcherOptions> );
w.ItemChanged += new ChangedEventHandler (ItemChangedHandler);
w.Enabled = true;
// Change notifications now arrive until we unsubscribe from the event
§
// Now we unsubscribe from the event
w.ItemChanged -= new ChangedEventHandler (ItemChangedHandler);
w.Dispose ();
§
// The change notification handler
void ItemChangedHandler (object source, ChangedEventArgs args) {
foreach (ItemChangeDetail detail in args.Details) {
switch (typeof(detail)) {
case ItemExtensionChangeDetail:
// handle added + modified + removed events for Item Extension
break;
case RelationshipChangeDetail:
// handle added + modified + removed events for Relationship
break;
default:
case ItemChangeDetail:
// handle added + modified + removed events for Item or Embedded Item
HandleItemChangeDetail (detail);
break;
}
}
|
void HandleItemChangeDetail (ItemChangeDetail detail) {
switch (detail.ChangeType) {
case Added: // handle added event
break;
case Modified: // handle modified event
break;
case Removed: // handle modified event
break;
}
}
Suporte a Blob e Stream
ApIs de suporte a blob e fluxo ainda estão em fluxo no momento desta gravação. Verifique a documentação para obter as informações mais recentes sobre como acessar blobs e fluxos no repositório do WinFS.
Cursor e paginação
Os vários Find
métodos nas classes WinFS podem retornar uma coleção (potencialmente) grande de objetos. Essa coleção é equivalente a um conjunto de linhas no mundo do banco de dados. Os aplicativos de banco de dados tradicionais usam um cursor paginado para navegar com eficiência em um conjunto de linhas grande. Esse cursor faz referência a uma única linha (um cursorfino) ou a um conjunto de linhas (um cursor de página). A ideia é que os aplicativos recuperem o valor de uma página de linhas por vez; eles também podem identificar uma linha dentro da página para atualização e exclusão posicionadas. A API do WinFS fornece abstrações semelhantes ao desenvolvedor para lidar com grandes coleções.
Por padrão, uma operação de localização fornece um cursor dinâmico somente leitura, rolável sobre a coleção retornada. Um aplicativo pode ter um cursor de mangueira de incêndio para desempenho máximo. Um cursor de mangueira de incêndio é um cursor somente para frente. O aplicativo pode recuperar uma página de linhas de cada vez, mas a próxima operação de recuperação começará com o conjunto subsequente de linhas. Ele não pode voltar e recuperar linhas. De certa forma, as linhas fluem do repositório para o aplicativo, como a água de uma mangueira de incêndio, daí o nome.
A CursorType
propriedade na FindParameters
classe permitirá que um aplicativo escolha entre uma mangueira de incêndio e um cursor rolável. Para cursores de mangueira de incêndio e roláveis, o aplicativo pode definir um tamanho de página usando a PageSize
propriedade da FindParameters
classe . Por padrão, o tamanho da página é definido como 1.
Associação de dados
Você pode usar as classes de dados do WinFS como fontes de dados em um ambiente de associação de dados. As classes WinFS implementam IDataEntity
interfaces (para objetos únicos) e IDataCollection
(para coleções). A IDataEntity
interface fornece notificações para o destino de associação de dados de alterações nas propriedades no objeto de fonte de dados. A IDataCollection
interface permite a determinação do tipo base de um objeto em uma coleção polimórfica. Ele também permite que você recupere um System.Windows.Data.CollectionManager
, que navega pelas entidades de dados da coleção e fornece uma exibição (por exemplo, ordem de classificação ou filtro) da coleção. Discuto a associação de dados em detalhes no Capítulo 5.
Segurança
O modelo de segurança do WinFS concede fundamentalmente um conjunto de Rights
para um Principal
em um Item
das seguintes maneiras:
- A segurança é definida no nível de
Items
. - Um conjunto de direitos pode ser concedido a um princípio de segurança em um
Item
. Esse conjunto inclui: READ, WRITE, DELETE, EXECUTE (para todos os itens), CREATE_CHILD, ADMINISTER e AUDIT. (Direitos adicionais são concedidos em Itens de pasta.) - Usuários e aplicativos são os princípios de segurança. Os direitos de aplicativo substituem os direitos do usuário. Quando um aplicativo não tem permissão para excluir um contato, um usuário não pode excluí-lo por meio do aplicativo, independentemente das permissões do usuário.
- A segurança é definida usando regras; cada regra é um
Grant
e se aplica a um trigêmeo: (<ItemSet, PrincipalSet, RightSet>
). - As regras são armazenadas como
Items
.
Obtendo direitos em um item
Cada classe de item do WinFS tem um método chamado GetRightsForCurrentUser
, que retorna o conjunto de direitos — READ, WRITE, DELETE e assim por diante — que o usuário atual tem no item especificado. Além disso, o método retorna o conjunto de métodos que o WinFS permite que o usuário execute.
Definindo direitos em um item
O WinFS usa um tipo de item especial, SecurityRule
, para armazenar informações de permissões em Items
. Portanto, definir e alterar direitos não é diferente de manipular qualquer outro Item
no WinFS. Aqui está um exemplo de código mostrando como definir direitos em um item de pasta:
using (ItemContext ctx = ItemContext.Open("\\localhost\WinFS_C$")) {
SecurityRule sr = new SecurityRule (ctx);
sr.Grant = true;
// set permission on items under folder1 including folder1
sr.AppliesTo = <folder1's Identity Key>;
sr.Condition = acl1; // a DACL
sr.Save();
}
Estendendo a API do WinFS
Cada classe interna do WinFS contém métodos padrão, como Find*
e tem propriedades para obter e definir valores de campo. Essas classes e métodos associados formam a base das APIs do WinFS e permitem que você aprenda a usar uma classe e saber, em geral, como usar muitas outras classes do WinFS. No entanto, embora o comportamento padrão seja útil, cada tipo de dados específico precisa de comportamentos adicionais específicos do tipo.
Comportamentos de domínio
Além desses métodos padrão, cada tipo winfs normalmente terá um conjunto de métodos específicos de domínio exclusivos para esse tipo. (Na verdade, a documentação do WinFS geralmente se refere a definições de tipo como esquema, refletindo o patrimônio do banco de dados do WinFS.) O WinFS refere-se a esses métodos específicos do tipo como comportamentos de domínio. Por exemplo, aqui estão alguns comportamentos de domínio no esquema de contatos:
- Determinar se um endereço de email é válido
- Dada uma pasta, obtendo a coleção de todos os membros da pasta
- Dada uma ID de item, obtendo um objeto que representa este item
- Dada uma pessoa, colocando sua status online
- Criando um novo contato ou um contato temporário com funções auxiliares
Comportamentos de Value-Added
Classes de dados com comportamentos de domínio formam uma base na qual os desenvolvedores de aplicativos se baseiam. No entanto, não é possível nem desejável que as classes de dados exponham todos os comportamentos concebíveis relacionados a esses dados.
Você pode fornecer novas classes que estendem a funcionalidade base oferecida pelas classes de dados do WinFS. Você faz isso escrevendo uma classe cujos métodos tomam uma ou mais classes de dados do WinFS como parâmetros. No exemplo a seguir, as OutlookMainServices
classes e WindowsMessageServices
hipotéticas que usam o WinFS MailMessage
padrão e Person
as classes:
MailMessage m = MailMessage.FindOne (…);
OutlookEMailServices.SendMessage(m);
Person p = Person.FindOne (…);
WindowsMessagerServices wms = new WindowsMessagerServices(p);
wms.MessageReceived += new MessageReceivedHandler (OnMessageReceived);
wms.SendMessage("Hello");
Em seguida, você pode registrar essas classes personalizadas com o WinFS. Os dados de registro serão associados aos metadados de esquema que o WinFS mantém para cada tipo de WinFS instalado. O WinFS armazena os metadados de esquema como itens do WinFS; portanto, você pode atualizar, consultar e recuperá-la como faria com todos os outros itens do WinFS.
Especificando restrições
O modelo de dados do WinFS permite restrições de valor em tipos. O WinFS avalia e impõe essas restrições quando você adiciona itens ao repositório. No entanto, às vezes, você deseja verificar se os dados de entrada satisfazem suas restrições sem incorrer na sobrecarga de uma viagem de ida e volta para o servidor. O WinFS permite que o autor do esquema/tipo decida se o tipo dá suporte à verificação de restrição do lado do cliente. Quando um tipo dá suporte à validação do lado do cliente, o tipo terá um método de validação que você pode chamar para verificar se um objeto atende às restrições especificadas. Observe que, independentemente de o desenvolvedor chamar o método , o Validate
WinFS ainda verifica as restrições na loja.
Usando a API do WinFS e o SQL
A API do WinFS permite que um desenvolvedor acesse o repositório WinFS usando conceitos conhecidos de CLR (Common Language Runtime). Ao longo deste capítulo, usei o seguinte padrão de codificação para acesso ao WinFS:
- Associar a um
ItemContext
. - Localize os itens desejados.
- Atualize os itens.
- Salve todas as alterações de volta no repositório.
A etapa 2 é essencialmente uma consulta para o repositório. A API do WinFS usa uma sintaxe de expressão de filtro com base em OPath
para especificar essas consultas. Em muitos casos, o uso de expressões de filtro deve ser suficiente para a maioria das tarefas. No entanto, haverá casos em que o desenvolvedor desejará usar toda a potência e flexibilidade do SQL.
Os seguintes recursos estão presentes no SQL, mas não estão disponíveis ao usar uma expressão de filtro:
- Agregação (
Group By
,Having
,Rollup
) - Projeção (incluindo expressões de seleção calculadas, distintas, IdentityCol, RowGuidCol)
- Para XML
- Union
- Opção
- Junção direita/completa/cruzada
- Seleções aninhadas
- Ingressar na tabela não WinFS
Portanto, é essencial que um desenvolvedor do WinFS possa fazer a transição direta entre a API SQLClient e a API do WinFS, usando um ou outro em vários locais no código.
Agregar e agrupar com SQL e, em seguida, usar a API do WinFS
Um dono de pequenas empresas, Joe, quer determinar quem são seus 10 melhores clientes e enviar cestas de presentes para eles. Suponha que Customer seja um tipo de item esquematizado. Isso significa que um ISV forneceu um esquema para o Tipo de cliente para WinFS e, portanto, isso também significa que um repositório WinFS agora pode conter itens do Cliente. Um item cliente tem um link de retenção para um tipo de Item de Pedido esquematizado. O Item de Pedido tem uma coleção inserida de Pedidos de Linha, da seguinte maneira:
1. using (ItemContext ctx = ItemContext.Open()) {
2.
3. SqlCommand cmd = ctx.CreateSqlCommand();
4. cmd.CommandText =
5. "select object(c) from Customers c inner join (" +
6. "select top 10 C.ItemId, sum(p.price) " +
7. "from Customers C" +
8. "inner join Links L on L.SourceId = C.ItemId" +
9. "inner join Orders O on L.TargetId = O.ItemId" +
10. "cross join unnest(O.LineOrders) " +
11. "group by C.ItemId" +
12. "order by sum(p.price)) t ON c.ItemId = t.ItemId";
13.
14. SqlDataReader rdr = cmd.ExecuteReader();
15.
16. GiftBasketOrder gbOrder = new GiftBasketOrder(Ö);
17.
18. while (rdr.Read()) {
19. Customer c = new Customer((CustomerData) rdr.GetValue(0));
20. // add the customer to gbOrder's recipient collection
21. gbOrder.Recipients.Add(c);
22. }
23.
24. // send the order. The ISV's GiftBasketOrder can easily pull out
25. // customer info such as shipping address from the Customer object
26. gbOrder.Send();
27. }
Na linha 1 deste exemplo, eu abro um contexto para a raiz do volume do sistema. Na linha 3, crio um objeto de comando SQL que posteriormente uso para executar uma consulta SQL no repositório WinFS. Esse objeto de comando reutiliza a conexão usada pelo contexto do item. As linhas 4 a 12 constroem a consulta e a linha 14 executa a consulta. A consulta retorna os 10 principais clientes da seguinte maneira: a instrução SELECT nas linhas 6 a 12 gera uma tabela agrupada que contém o valor total dos pedidos de cada cliente; A cláusula ORDER BY na linha 12, combinada com o modificador TOP 10 na linha 6, seleciona apenas os 10 principais clientes nesta tabela agrupada.
A GiftBasketOrder
classe é uma classe personalizada que usa o objeto de API Customer
do WinFS. Eu crio uma instância da GiftBasketOrder
linha 16.
A linha 19 usa o SQLDataReader
para ler a primeira coluna do conjunto de linhas retornado e converte-a em um CustomerData
objeto .
Ao definir um novo tipo no WinFS (conhecido como criando um novo esquema), você está definindo dois tipos: sua classe gerenciada e o formato persistente da classe do repositório WinFS. O WinFS sempre adiciona o sufixo Data ao nome da classe para criar o nome do tipo do repositório. Portanto, por exemplo, quando você define um novo tipo de cliente que reside no repositório WinFS, o WinFS cria o UDT (Tipo Definido pelo Usuário) do WinFS paralelo CustomerData
.
A primeira coluna do conjunto de linhas contém o objeto do repositório CustomerData
. Passo esse objeto para o construtor da Customer
classe e o construtor inicializa o novo objeto do CustomerData
objeto . Este exemplo é típico de usar UDTs de armazenamento para construir objetos de API do WinFS.
A linha 24 adiciona o cliente à Recipients
coleção do GiftBasketOrder
.
Por fim, uso o Send
método em gbOrder para "enviar" essa ordem.
Navegue na API e, em seguida, agregar no SQL
Suponha que você queira encontrar o salário médio (durante um período de 10 anos) para o CEO de cada empresa na minha carteira. Use as seguintes suposições:
- Tenho uma pasta chamada Empresas em Meu Portfólio, que contém itens do tipo Organização.
-
EmployeeData
é uma relação baseada em vínculo, e tem umYearlyEmploymentHistory
que tem o ano e o salário para esse ano.
1. using (ItemContext ctx = ItemContext.Open(@"Companies In My Portfolio")) {
2.
3. SqlCommand cmd = ctx.CreateCommand();
4. cmd.CommandText =
5. "select avg( Salary ) from Links l cross apply " +
6. "( select Salary from unnest( convert(" +
7. "EmployeeData,l.LinkCol)::YearlyEmploymentHistory )" +
8. "where Year >= '1993' ) where l.LinkID = @LinkID";
9.
10. SqlParameter param = new SqlParameter ("@LinkID", SqlDbType.BigInt);
11. cmd.Parameters.Add (param);
12.
13. Folder f = Folder.FindByPath (ctx, ".");
14.
15. FindResult orgs = f.GetMembersOfType (typeof(Organization));
16. foreach (Organization o in orgs) {
17. EmployeeData ed = EmployeeData.FindEmployeeInRole (o,
18. Organization.Categories.CeoRole);
19. param.Value = ed.Link.LinkID;
20. SqlDataReader rdr = cmd.ExecuteReader ();
21. rdr.Read ();
22. Console.WriteLine ("{0} ${1}",
23. ((Person)ed.Target).PersonalNames[0].FullName, rdr.GetFloat(0) );
24. rdr.Close ();
25. }
26. }
A Linha 1 abre um contexto para o compartilhamento WinFS Companies In My Portfolio. As linhas 3 a 11 criam uma consulta SQL parametrizada que posso usar no contexto da pasta. Essa consulta retorna o salário médio de um determinado funcionário (representado pelo @LinkID
parâmetro ). As linhas 10 e 11 especificam que @LinkID
é um parâmetro do tipo BigInt
. Executarei essa consulta posteriormente no exemplo, na linha 20.
A linha 13 obtém um Folder
objeto que representa a pasta indicada pelo compartilhamento que eu especifiquei ao criar o contexto. As linhas 15 e 16 configuram o loop para percorrer a coleção de Organization
objetos nessa pasta.
Para cada organização, a linha 17 obtém o EmployeeData
objeto para o CEO.
A linha 19 se prepara para a consulta e define o valor do parâmetro como o LinkID apropriado e, em seguida, a linha 20 executa o SELECT parametrizado.
A linha 21 lê a linha seguinte e única do resultado da consulta e as linhas 22 e 23 imprimem o nome do CEO e o salário médio de 10 anos.
Resumo
O armazenamento de dados do WinFS fornece um modelo de armazenamento de dados muito mais avançado do que os sistemas de arquivos tradicionais. Como ele dá suporte a dados, comportamento e relações, é difícil categorizar o WinFS como um sistema de arquivos, um banco de dados relacional ou um banco de dados de objeto. É um pouco de todas essas tecnologias em um produto. O WinFS fornece uma definição comum de informações onipresentes que são visíveis globalmente e estão disponíveis para todos os aplicativos em execução no Longhorn. Os aplicativos podem aproveitar os recursos de consulta, recuperação, atualização transacional e filtragem do WinFS; Portanto, o desenvolvedor gasta menos tempo desenvolvendo o acesso a dados e o código de armazenamento e mais tempo trabalhando na funcionalidade exclusiva do aplicativo.