Condividi tramite


Capitolo 4: Archiviazione

 

Introduzione
Capitolo 1: Modello di applicazione "Longhorn"
capitolo 2: Creazione di un'applicazione "Longhorn"
capitolo 3: Controlli e XAML

Capitolo 4: Archiviazione

Rettore di Brent
Wise Owl Consulting

Gennaio 2004

UPDATE: nonostante ciò che può essere dichiarato in questo contenuto, "WinFS" non è una funzionalità che verrà visualizzata con il sistema operativo Longhorn. Tuttavia, "WinFS" sarà disponibile sulla piattaforma Windows in una data futura, motivo per cui questo articolo continua a essere fornito per le tue informazioni.

Contenuto

Che cos'è WinFS?
Modello di programmazione WinFS
Uso dell'API WinFS e di SQL
Sommario

In alcuni modi, personal computer è un nome inadeguato. La maggior parte delle persone non usa un personal computer per calcolare. Utilizzano un computer per comunicare (tramite posta elettronica o messaggistica istantanea) e per archiviare e organizzare i dati personali (ad esempio posta elettronica, documenti, immagini e musica digitale). Purtroppo, mentre il computer attualmente archivia questi dati abbastanza bene, fa un lavoro relativamente scadente di consentire di organizzare le informazioni in modo da poterli trovare in un secondo momento.

La capacità del disco è cresciuta a circa il 70% ogni anno nell'ultimo decennio. Attualmente è possibile acquistare unità con più di 250 gigabyte (GB) di spazio di archiviazione. È probabile che nei prossimi anni saranno disponibili 500 GB di unità e che molti sistemi avranno più di un'unità disco. Ho appena fatto un rapido controllo sul computer su cui scrivo questo capitolo, e ho 283.667 file in 114.129 cartelle in soli 200 GB di spazio su disco. Quando dimentico esattamente dove ho messo un file, può richiedere un po 'di tempo per trovarlo di nuovo. Nel peggiore dei casi, devo cercare l'intero contenuto di ogni disco. In pochi anni, le persone saranno in grado di archiviare milioni di file, la maggior parte dei quali, se nulla migliora, non vedranno mai più.

Un motivo per cui le persone hanno difficoltà a trovare informazioni sul computer è dovuto alla capacità limitata per l'utente di organizzare i dati. Il supporto del file system presente per cartelle e file funzionava correttamente originariamente perché era un paradigma familiare per la maggior parte delle persone e il numero di file era relativamente piccolo. Tuttavia, non consente facilmente di archiviare un'immagine del tuo collega Bob giocando softball al picnic aziendale 2007 in un parco locale e in seguito trovare l'immagine durante la ricerca di documenti che:

  • Menzionare Bob
  • Coinvolgere gli sport
  • Correlare agli eventi aziendali
  • Per quanto riguarda il parco o la sua zona circostante
  • Sono stati creati nel 2007

La struttura di cartelle gerarchica non funziona correttamente quando si vogliono classificare i dati in diversi modi. Pertanto, abbiamo un problema oggi in quanto abbiamo un sacco di roba da archiviare e non è un buon modo per classificarlo. Oltre a categorizzare le informazioni, che molte persone associano a un set fisso di parole chiave ai dati, le persone devono correlare i dati. Ad esempio, potrei voler correlare un'immagine al pic-nic dell'azienda, o potrei voler correlare una foto a Bob, che è anche membro di un'organizzazione a cui dono tempo e impegno, come contatto.

Un altro problema è che archiviamo la stessa roba in più posizioni in più formati. Gli sviluppatori dedicano molto tempo e fatica a creare astrazioni di archiviazione specifiche per informazioni quotidiane, ad esempio Persone, Luoghi, Tempi ed Eventi. Ad esempio, Microsoft Outlook ha una definizione di contatto. La Rubrica di Microsoft Windows ha anche la propria definizione di un contatto. Ogni applicazione di messaggistica istantanea ha ancora un altro. Ogni applicazione archivia la definizione di un contatto in un silo isolato univoco di informazioni.

Esistono diversi problemi con gli approcci correnti all'archiviazione dei dati, tra cui i seguenti:

  • Gli sviluppatori reinventano ripetutamente le astrazioni dei dati di base.
  • Più applicazioni non possono condividere facilmente dati comuni.
  • Le stesse informazioni si trovano in più posizioni.
  • L'utente immette ripetutamente le stesse informazioni.
  • Le copie separate dei dati diventano non sincronizzate.
  • Non sono presenti notifiche di modifica dei dati.

Che cos'è WinFS?

WinFS è il nuovo sistema di archiviazione in Longhorn. Migliora la piattaforma Microsoft Windows in tre modi. In primo luogo, consente di classificare le informazioni in più modi e di correlare un elemento di informazioni a un altro. In secondo luogo, fornisce un formato di archiviazione comune per le informazioni raccolte quotidianamente, ad esempio informazioni che riguardano persone, luoghi, immagini e altro ancora. In terzo luogo, promuove la condivisione dei dati di informazioni comuni tra più applicazioni di più fornitori.

WinFS è una piattaforma di archiviazione

WinFS è una piattaforma di archiviazione attiva per organizzare, cercare e condividere tutti i tipi di informazioni. Questa piattaforma definisce un modello di dati avanzato che consente di usare e definire tipi di dati avanzati che la piattaforma di archiviazione può usare. WinFS contiene numerosi schemi che descrivono entità reali, ad esempio immagini, documenti, persone, luoghi, eventi, attività e messaggi. Queste entità possono essere piuttosto complesse. Ad esempio, una persona può avere più nomi, più indirizzi fisici e di posta elettronica, una posizione corrente e molto altro ancora.

I fornitori di software indipendenti (ISV) possono anche definire nuovi tipi di dati e fornire il proprio schema a WinFS. Consentendo a WinFS di gestire problemi di archiviazione complessi, un ISV può concentrarsi sullo sviluppo della logica unica dell'applicazione e sfruttare le funzionalità di archiviazione più avanzate di WinFS per i dati quotidiani e personalizzati.

WinFS contiene un motore relazionale che consente di individuare istanze di tipi di archiviazione usando query relazionali avanzate. WinFS consente di combinare queste entità di archiviazione in modi significativi usando le relazioni. Un contatto può essere membro del gruppo Dipendente di un'organizzazione, mentre contemporaneamente un membro del gruppo Famiglia per un indirizzo specifico. Gli ISV ottengono automaticamente la possibilità di cercare, replicare, proteggere e stabilire relazioni tra i tipi di dati univoci e tra i tipi di dati Windows predefiniti.

Questa struttura consente all'utente di porre domande al sistema e chiederle di individuare le informazioni anziché chiedere al sistema di cercare singolarmente le cartelle. Ad esempio, puoi chiedere a WinFS di trovare tutti i messaggi di posta elettronica delle persone nella tua lista di amici di messaggistica istantanea per cui non hai un numero di telefono. Usando le query relazionali, è possibile trovare tutti i membri di una famiglia per un determinato dipendente con un compleanno nel mese corrente.

WinFS supporta anche più modelli di programmazione flessibili che consentono di scegliere l'API (Application Programming Interface) appropriata per l'attività. È possibile accedere all'archivio usando query relazionali tradizionali usando il linguaggio SQL (Structured Query Language). In alternativa, è possibile usare classi e oggetti .NET per accedere all'archivio dati. È anche possibile usare le API basate su XML nell'archivio dati. WinFS supporta anche l'accesso ai dati tramite l'API di file system Microsoft Win32 tradizionale. È anche possibile combinare e trovare corrispondenze, ovvero usare più API per una singola attività. Tuttavia, per la maggior parte degli scopi, gli sviluppatori useranno le API della classe gestita per modificare i dati nell'archivio WinFS. Spesso sarà molto più complesso eseguire un aggiornamento usando istruzioni SQL non elaborate rispetto all'uso delle API dell'oggetto.

WinFS offre inoltre un set di servizi dati per il monitoraggio, la gestione e la modifica dei dati. È possibile registrarsi per ricevere eventi quando vengono modificati determinati elementi di dati. È possibile pianificare WinFS per replicare i dati in altri sistemi.

WinFS è un file system

Per i dati tradizionali basati su file, ad esempio documenti di testo, tracce audio e clip video, WinFS è il nuovo file system di Windows. In genere, si archivieranno i dati principali di un file, il flusso di file, come file in un volume NTFS. Tuttavia, ogni volta che chiami un'API che modifica o aggiunge elementi con parti del flusso di file NTFS, WinFS estrae i metadati dal flusso e aggiunge i metadati all'archivio WinFS. Questi metadati descrivono informazioni sul flusso, ad esempio il relativo percorso, oltre a tutte le informazioni che WinFS possono estrarre dal flusso. A seconda del contenuto del file, questi metadati possono essere l'autore (di un documento), il genere (di un file audio), le parole chiave (da un file PDF) e altro ancora. WinFS sincronizza il flusso di file residente ntfs e i metadati residenti in WinFS. Le nuove applicazioni Longhorn possono anche scegliere di archiviare i flussi di file direttamente in WinFS. È possibile accedere ai flussi di file usando l'API del file system Win32 esistente o la nuova API WinFS.

WinFS non è solo un file system

Un file system gestisce file e cartelle. Anche se WinFS gestisce file e cartelle, gestisce anche tutti i tipi di dati non basati su file, ad esempio contatti personali, calendari eventi, attività e messaggi di posta elettronica. I dati WinFS possono essere strutturati, semistrutturati o non strutturati. I dati strutturati includono uno schema che definisce anche i dati per e come usarli. Poiché WinFS è, in parte, un sistema relazionale, applica l'integrità dei dati in relazione alla semantica, alle transazioni e ai vincoli.

WinFS non è solo un sistema relazionale. Supporta sia l'archiviazione gerarchica che l'archiviazione relazionale. Supporta la restituzione di dati come tipi strutturati e come oggetti, ovvero tipi e comportamento. È possibile considerare WinFS un sistema di archiviazione dei dati gerarchico, relazionale e orientato agli oggetti, anche se in realtà contiene alcuni aspetti di ognuno di questi sistemi di archiviazione tradizionali. WinFS si estende oltre il file system tradizionale e il sistema di database relazionale. È l'archivio per tutti i tipi di dati nella piattaforma Windows più recente.

WinFS e NTFS

È possibile archiviare un file nel file system NTFS tradizionale o nel nuovo archivio dati WinFS proprio come è possibile archiviare le cose in FAT32 o in CD-ROMs o in NTFS oggi. In genere, un file archiviato in NTFS non è visibile in WinFS. Le applicazioni Longhorn che usano le nuove API WinFS possono accedere ai dati archiviati in WinFS o in NTFS. Inoltre, le applicazioni Longhorn possono continuare a usare l'API Win32 per accedere ai dati archiviati nel file system NTFS.

Promozione file

I file sono in WinFS o no. Qualsiasi elemento con una parte del flusso di file può partecipare a innalzamento di livello/abbassamento di livello, che in genere chiamiamo la gestione dei metadati. Quando WinFS promuove un file, estrae i metadati dal contenuto del file NTFS noto e aggiunge i metadati all'archivio dati WinFS. Il flusso di dati effettivo del file rimane nel file system NTFS. È quindi possibile eseguire query su WinFS per quanto riguarda i metadati come se il file risieda in modo nativo all'interno di WinFS. WinFS rileva anche le modifiche nel file NTFS e aggiorna i metadati all'interno dell'archivio dati WinFS in base alle esigenze.

Importazione ed esportazione di file

È anche possibile importare un file in WinFS da NTFS ed esportare un file da WinFS a NTFS. L'importazione e l'esportazione di un file sposta sia il contenuto del file che i metadati. Dopo l'importazione o l'esportazione, il nuovo file è completamente indipendente dal file originale.

Modello di programmazione WinFS

Il modello di programmazione WinFS include l'accesso ai dati, la manipolazione dei dati, l'estendibilità della classe di dati WinFS, la sincronizzazione dei dati, le notifiche di modifica dei dati e la definizione delle priorità degli eventi. L'accesso ai dati e la manipolazione dei dati consentono di creare, recuperare, aggiornare ed eliminare i dati archiviati all'interno di WinFS e di esercitare comportamenti specifici del dominio. L'estendibilità della classe di dati consente di estendere gli schemi WinFS con campi personalizzati e tipi personalizzati. La sincronizzazione dei dati consente di sincronizzare i dati tra gli archivi WinFS e tra un archivio WinFS e un archivio non WinFS.

La parte superiore della gerarchia del modello di dati WinFS è un servizio WinFS, che è semplicemente un'istanza di WinFS. Un livello nella gerarchia del servizio è un volume . Un volume è il contenitore autonomo più grande di elementi. Ogni istanza di WinFS contiene uno o più volumi. All'interno di un volume sono elementi.

WinFS introduce l'elemento come nuova unità di coerenza e funzionamento, anziché come file. Il sistema di archiviazione archivia gli elementi. È possibile eseguire query avanzate sugli elementi. Un elemento è effettivamente un tipo di base del sistema di archiviazione. Un elemento ha quindi un set di attributi di dati e offre una funzionalità di query di base.

Le persone in genere organizzano i dati nel mondo reale in base ad alcuni sistemi che hanno senso in un determinato dominio. Tutti questi sistemi partizionano i dati in gruppi denominati. WinFS modella questa nozione con il concetto di una cartella . Una cartella è un tipo speciale di elemento. Esistono due tipi di cartelle: cartelle di contenimento e cartelle virtuali.

Una cartella di contenimento è un elemento che contiene collegamenti ad altri elementi e modella il concetto comune di una cartella del file system. Un elemento esiste fino a quando almeno un collegamento contiene riferimenti. Si noti che una cartella di contenimento non contiene direttamente gli elementi presenti logicamente nella cartella, ma contiene collegamenti a tali elementi. Ciò consente a più cartelle di contenimento di contenere stesso elemento.

Una cartella virtuale è una raccolta dinamica di elementi. Si tratta di un set denominato di elementi. È possibile enumerare il set in modo esplicito o specificare una query che restituisce i membri del set. Una cartella virtuale specificata da una query è piuttosto interessante. Quando si aggiunge un nuovo elemento all'archivio che soddisfa i criteri della query per una cartella virtuale, il nuovo elemento viene automaticamente membro della cartella virtuale. Una cartella virtuale è un elemento. Concettualmente, rappresenta un set di collegamenti non di controllo agli elementi, come illustrato nella figura 4-1.

Figura 4-1. Gerarchia del modello di dati WinFS

In alcuni casi, è necessario modellare una nozione di contenimento altamente vincolata, ad esempio un documento di Microsoft Word incorporato in un messaggio di posta elettronica è, in un certo senso, legato più strettamente al relativo contenitore che, ad esempio, un file contenuto all'interno di una cartella. WinFS esprime questa nozione usando elementi incorporati. Un elemento incorporato è un tipo speciale di collegamento all'interno di un elemento (denominato Collegamento incorporato) che fa riferimento a un altro elemento. L'elemento a cui si fa riferimento può essere associato o modificato in altro modo solo all'interno del contesto dell'elemento contenitore.

Infine, WinFS fornisce la nozione di categorie come modo per classificare gli elementi. È possibile associare una o più categorie a ogni elemento in WinFS. WinFS, in effetti, contrassegna il nome della categoria nell'elemento. È quindi possibile specificare il nome della categoria nelle ricerche. Il modello di dati WinFS consente la definizione di una gerarchia di categorie, consentendo così una classificazione ad albero dei dati.

Organizzazione delle informazioni

Tutte queste funzionalità consentono di organizzare le informazioni in WinFS in cinque modi:

  • Organizzazione gerarchica basata su cartelle. Con questo approccio, è ancora disponibile la struttura tradizionale della cartella gerarchica e dell'organizzazione degli elementi. Tutti gli elementi in un archivio dati WinFS devono trovarsi in un contenitore e uno di questi tipi di contenitore è una cartella.
  • Organizzazione basata sui tipi. Un elemento è sempre di un tipo specifico. Ad esempio, si dispone di elementi persona, elementi di foto, elementi dell'organizzazione e molti altri tipi disponibili. È anche possibile creare nuovi tipi e archiviarli nell'archivio dati WinFS.
  • Organizzazione basata su proprietà dell'elemento. È possibile visualizzare gli elementi con una o più proprietà impostate su valori specificati. Si tratta, in effetti, di una visualizzazione cartella virtuale con una query che restituisce gli elementi con il valore specificato per le proprietà specificate.
  • Organizzazione basata sulle relazioni. È possibile recuperare gli elementi in base alla relazione con altri elementi, ad esempio una persona può essere membro di un'organizzazione e può essere organizzata o cercata in termini di relazione.
  • Organizzazione basata su categorie. È possibile creare e associare un numero qualsiasi di parole chiave definite dall'utente a un elemento. Successivamente è possibile recuperare gli elementi con un valore specifico per una parola chiave associata. Non sarà tuttavia possibile creare tassonomie di categorizzazione, quindi questa tecnica dell'organizzazione non è così potente degli approcci precedenti.

API WinFS

WinFS offre tre API di accesso ai dati: l'API WinFS gestita, l'API ADO.NET e l'API Win32. L'API WinFS è un'API di alto livello fortemente tipizzata. ADO.NET fornisce un'API di livello inferiore per l'uso dei dati come XML o come tabelle o righe. Usando ADO.NET, è possibile accedere ai dati archiviati in WinFS usando Transact-Structured linguaggio di query (T-SQL) e, quando si desidera, recuperare i dati in XML usando la funzionalità FOR XML di T-SQL. L'API Win32 consente l'accesso ai file e alle cartelle archiviati in WinFS.

È consigliabile usare più modelli di accesso per risolvere un problema. Ad esempio, è possibile eseguire una query T-SQL che restituisce un set di contatti come oggetti gestiti del tipo di contatto WinFS. Indipendentemente dall'API usata, ogni API modifica i dati nell'archivio WinFS usando T-SQL.

In molti casi, si preferisce usare l'API WinFS gestita. Queste classi .NET Framework eseguono automaticamente il mapping delle relazioni tra oggetti necessari per eseguire la conversione tra costrutti di programmazione orientati agli oggetti ed eseguono il T-SQL necessario per ottenere l'accesso ai dati WinFS.

Uso delle classi WinFS gestite

Le classi gestite WinFS risiedono nello spazio dei nomi System.Storage e nei relativi spazi dei nomi annidati. Molte applicazioni useranno anche definizioni di tipo WinFS dallo spazio dei nomi System.Storage.Core. È anche possibile usare tipi di spazi dei nomi più specializzati. Ad esempio, le classi gestite che modificano la definizione di sistema di un contatto risiedono nello spazio dei nomi System.Storage.Contact. Per semplicità, tutti gli esempi di codice in questo capitolo useranno il set di dichiarazioni di using seguente:

using System.Storage;
using System.Storage.Core;
using System.Storage.Contact;

ItemContext

L'archivio WinFS è costituito da elementi organizzati in cartelle e categorizzati. Il primo passaggio nell'uso di WinFS consiste nell'identificare il set di elementi con cui si vuole lavorare. Questo processo viene chiamato bindinge il set di elementi può essere uno dei seguenti:

  • Un intero volume (noto anche come cartella radice )
  • Subset identificabile di elementi in un determinato volume, ad esempio una particolare cartella di contenimento o una cartella virtuale
  • Un singolo elemento
  • Una condivisione WinFS (che identifica un volume, una cartella, una cartella virtuale o un singolo elemento)

Per eseguire il binding a un set di elementi, creare un oggetto System.Storage.ItemContext e connetterlo a un archivio dati WinFS. Utilizzare il metodo helper System.Storage.ItemContext.Open statico per creare un oggetto ItemContext.

Il codice seguente crea un ItemContext che si connette al volume WinFS locale predefinito. Il valore predefinito è \\local-computer-name\DefaultStore share:

System.Storage.ItemContext ctx = System.Storage.ItemContext.Open ();
§
ctx.Close();

In alternativa, puoi passare una stringa al costruttore per connettere il contesto dell'elemento a un archivio WinFS specifico. Il codice seguente crea un contesto di elemento connesso a una condivisione WinFS identificata dalla condivisione \\machine\Documenti legali:

ItemContext ctx = null;
try {
ctx = ItemContext.Open (@"\machine\Legal Documents");
  §
}
finally {
  if (ctx != null) ctx.Dispose();
}

Assicurarsi di chiudere o eliminare l'oggetto contesto non appena si termina l'uso indipendentemente dalle eccezioni. Un ItemContext usa risorse non gestite significative, ad esempio una connessione all'archivio, che è consigliabile liberare in modo tempestivo. Per rendere i contesti di chiusura il più comodo possibile, la classe ItemContext implementa l'interfaccia IDisposable. È quindi possibile usare l'istruzione using C# come illustrato nell'esempio seguente per rilasciare queste risorse:

using (ItemContext ctx = ItemContext.Open (@"D:\MyStore")) {
§
}

Archiviazione di un nuovo elemento in un archivio dati WinFS

Ogni elemento in un archivio dati WinFS deve essere un membro di una cartella dell'archivio. Per ottenere la radice della gerarchia di cartelle, chiamare il metodo statico estremamente denominato System.Storage.Folder.GetRootFolder. Esistono tuttavia anche diversi contenitori definiti dal sistema per l'archiviazione di dati specifici dell'applicazione. Spesso si usa uno dei metodi statici nella classe UserDataFolder per recuperare una cartella in cui inserire nuovi elementi.

Recupero di una cartella

Nell'esempio seguente, troverò la cartella Contatti personali dell'utente corrente, se esistente e la creerò quando non esiste. Si noti che si tratta di un esempio piuttosto contrivo: il sistema crea automaticamente la cartella Contatti personali di un utente se non esiste quando l'utente accede per la prima volta a un sistema, ma mi dà la possibilità di mostrare come creare una cartella prevista quando non esiste.

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();
}

Il codice precedente esegue diverse operazioni interessanti. In primo luogo, cerco di individuare una cartella esistente contenuta nella gerarchia di cartelle dati personali dell'utente. Non sto cercando la cartella con un nome noto. Si individua invece la cartella all'interno dell'albero dei dati personali dell'utente associato in precedenza alla categoria nota PersonalContactsFolder. La shell visualizza questa cartella quando si seleziona Contatti personali.

Questa cartella esiste già, ma in caso contrario, si recupera la cartella radice per la gerarchia dei dati dell'utente. Creo un nuovo elemento, di tipo WellKnownFoldere quindi creo un riferimento a una categoria nota, ovvero la categoria PersonalContactsFolder. Impostare quindi il tipo della nuova cartella sul tipo di categoria PersonalContactsFolder e infine aggiungere la nuova cartella alla cartella contenitore, ovvero la cartella radice dei dati personali dell'utente. WinFS non salva le modifiche apportate all'archivio dati fino a quando non chiami Update nel contesto dell'elemento (che dimentico regolarmente).

Naturalmente, questo è il modo dettagliato per trovare la cartella Contatti personali. Volevo mostrarti come funzionano le cose. In genere, usarei invece il codice seguente. Il metodo FindMyPersonalContactsFolder trova la cartella esistente.

WellKnownFolder userDataFolder =
         UserDataFolder.FindMyPersonalContactsFolder (ctx);

Creazione di un nuovo elemento

Poiché ora ho la cartella Contatti personali, sembra appropriato creare un nuovo contatto nella cartella. Nell'esempio seguente si creerà un numero di contatti persona e li si aggiungerà alla cartella :

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 ();
}

Il codice precedente usa il metodo Person.CreatePersonalContact statico. Questo metodo

  • Crea un nuovo elemento Person nel contesto dell'elemento specificato
  • Crea una nuova relazione FolderMember con il nome specificato che fa riferimento alla persona
  • Aggiunge la relazione FolderMember alla raccolta di RelationshipPersonalContactsFolder

Successivamente aggiorno le proprietà DisplayName, GivenNamee Surname dell'elemento Person. Come sempre, chiamo Update nel contesto dell'elemento per salvare le modifiche nell'archivio dati.

Esaminiamo più attentamente il metodo CreatePersonalContact. Equivale a quanto segue:

// 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 ();

Elementi delle relazioni

WinFS definisce un modello di dati di relazione che consente di correlare gli elementi tra loro. Quando si definisce lo schema per un tipo di dati, è possibile definire zero o più relazioni come parte dello schema. Ad esempio, lo schema Folder definisce la relazione FolderMember. Lo schema Organization definisce la relazione Employee. Per ogni relazione definita, è presente una classe che rappresenta la relazione stessa. Questa classe è derivata dalla classe Relationship e contiene membri specifici del tipo di relazione. Esiste anche una classe di raccolta "virtuale" fortemente tipizzata. Questa classe è derivata da VirtualRelationshipCollection e consente di creare ed eliminare istanze di relazione.

Una relazione correla un elemento di origine a un elemento di destinazione. Nell'esempio precedente, la cartella Contatti personali è l'elemento di origine e l'elemento Person è l'elemento di destinazione. La relazione FolderMember indica fondamentalmente che l'elemento Person è correlato alla cartella Contatti personali come membro della cartella.

Quando si definisce una relazione, si definisce se la relazione mantiene l'elemento di destinazione esistente, ovvero un che mantiene una relazione, o non mantiene l'elemento di destinazione in esistenza, una relazione di riferimento . Quando si crea una relazione di controllo a un elemento di destinazione, WinFS incrementa un conteggio dei riferimenti per l'elemento di destinazione. Quando WinFS elimina una relazione di controllo, decrementa il conteggio dei riferimenti sull'elemento di destinazione. Un elemento non esiste più nell'archivio quando il conteggio dei riferimenti raggiunge lo zero. WinFS non modifica mai il conteggio dei riferimenti della destinazione quando si crea o si elimina una relazione di riferimento alla destinazione. Pertanto, l'elemento di destinazione può scomparire dall'archivio quando il conteggio dei riferimenti raggiunge zero e la relazione potrebbe fare riferimento a un elemento non più esistente.

WinFS definisce la relazione FolderMember come relazione di controllo. La maggior parte delle altre classi di relazione sono relazioni di riferimento.

Elementi cartella

Ora che si conoscono gli elementi di collegamento, è possibile perfezionare la descrizione degli elementi della cartella. Una cartella è un elemento WinFS con una raccolta di elementi Link. La destinazione di ogni elemento Link nella raccolta è un membro della cartella . La proprietà Folder.Members rappresenta questa raccolta di collegamenti.

Si noti che offre una cartella WinFS molto più flessibile rispetto alle cartelle di file system tradizionali. I membri di una cartella possono essere file e elementi non di file. Più collegamenti a un determinato elemento possono risiedere in più cartelle contemporaneamente. In altre parole, più cartelle possono contenere stesso elemento.

Altri tipi di elemento

In genere, crei altri tipi di elementi nell'archivio WinFS come hai fatto negli esempi precedenti. Ogni tipo ha occasionalmente un proprio modello di utilizzo speciale. Ad esempio, è possibile avere organizzazioni come membri della cartella Contatti personali, quindi è possibile crearne una:

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;
}

A questo punto si aggiungerà un dipendente all'organizzazione:

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 ();
}

Analogamente, è possibile creare famiglie nelle cartelle Contatti personali. Si noti che una famiglia non implica una famiglia. Una famiglia potrebbe essere un gruppo di compagni di stanza. WinFS ha uno schema aggiuntivo per le famiglie, ma lo lascerò come esercizio per il lettore.

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);
}

L'esempio precedente usa un concetto non ancora discusso. Si noti l'uso della proprietà ItemID_Key in questa riga di codice:

  hhmd.Target_Key = p1.ItemID_Key;

Fondamentalmente, il valore ItemID_Key è un altro modo per fare riferimento a un elemento nell'archivio WinFS, quindi esaminiamo i modi per trovare gli elementi nello store.

Come trovare elementi

Naturalmente, non è molto utile posizionare gli elementi in un archivio dati se successivamente non è possibile trovarli facilmente. La classe ItemContext contiene metodi di istanza che è possibile usare per recuperare gli elementi in un archivio dati WinFS. Specificare il tipo di elemento da trovare ed eventuali vincoli speciali che gli elementi restituiti devono soddisfare. Inoltre, ogni classe di elementi, ad esempio, Person, File, Foldere così via, contiene anche metodi statici che consentono di trovare elementi di quel particolare tipo.

Il metodo FindAll restituisce uno o più elementi che corrispondono ai criteri specificati. Il metodo di istanza ItemContext.FindAll richiede di specificare il tipo di elementi da individuare. Inoltre, è possibile specificare facoltativamente i criteri di ricerca per restringere l'ambito della ricerca. Ad esempio, il codice seguente trova tutti gli elementi Person con una proprietà DisplayName il cui valore inizia con "Brent".

FindResult res = ctx.FindAll (typeof(Person), "DisplayName='Brent%'");
foreach (Person p in res) {
    // Use the Person item somehow
}

In alternativa, è possibile usare il metodo FindAll statico della classe Person come segue:

FindResult res = Person.FindAll (ctx, "DisplayName='Brent%'");
foreach (Person p in res) {
    // Use the Person item somehow
}

In entrambi questi esempi, il metodo FindAll restituisce sempre una raccolta di elementi corrispondenti al tipo e ai criteri specificati. Questa raccolta potrebbe non contenere elementi, ma non si riceve un riferimento Null per il FindResult. Di conseguenza, eseguire sempre l'iterazione sulla raccolta per ottenere gli elementi trovati.

Quando si sa che solo un singolo elemento corrisponderà ai criteri di filtro richiesti e specificati, è possibile usare il metodo FindOne. Prestare attenzione, tuttavia, il metodo FindOne genera un'eccezione quando trova più di un elemento che corrisponde alla richiesta.

Person p = Person.FindOne (ctx, "DisplayName='Brent Rector'");

Il secondo parametro stringa è un'espressione di filtro che consente di specificare vincoli aggiuntivi che gli elementi restituiti devono soddisfare. Il formato di base dell'espressione di filtro è una stringa nel formato "<propertyName> <operator> <propertyValue>".

WinFS chiama l'espressione un'espressione OPath. La sintassi è simile, anche se non identica, alla sintassi dell'espressione XPath usata per identificare gli elementi in un documento XML. Questo frammento di codice restituisce tutti gli elementi file per i file con estensione "doc" o "txt":

FindResult Files = File.FindAll (ctx, "Extension='doc' || Extension='txt'");

Queste espressioni possono essere piuttosto complesse. Ad esempio, l'istruzione seguente restituisce tutti gli elementi Person che rappresentano i dipendenti di un datore di lavoro con il DisplayName di "Main Benefit":

string pattern = "Source(EmployeeOf).DisplayName='Main Benefit'";
FindResult result = Person.FindAll (ctx, pattern);

Ecco un altro. Voglio gli elementi Person in cui il cognome non è "Ranier" e gli indirizzi di posta elettronica non terminano con ".edu".

string filter = "PersonalNames[Surname!='Ranier'] &&
                 !(PersonalEmailAddresses[Address like '%.edu'])");
FindResult result = Person.FindAll (ctx, filter);

Identificazione di un elemento specifico

Spesso è necessario creare riferimenti agli elementi nell'archivio WinFS. Infine, si usano questi riferimenti per individuare l'elemento appropriato. In precedenza in questo capitolo vi ho mostrato come usare un collegamento per fare riferimento a un elemento. I collegamenti usano un'identità descrittiva basata su stringhe per il riferimento e questo nome di stringa deve essere univoco all'interno della cartella contenitore del collegamento. In altre parole, sono necessari sia la cartella che uno dei relativi collegamenti contenuti per identificare l'elemento a cui si fa riferimento.

Tuttavia, è possibile creare più collegamenti con lo stesso nome descrittivo della stringa, purché i collegamenti vengano aggiunti a cartelle diverse in modo che tutti i nomi all'interno di una singola cartella rimangano univoci. Si noti che questi più collegamenti con lo stesso nome descrittivo non devono effettivamente fare riferimento allo stesso elemento di destinazione. Potrebbero, ma non devono.

In questi casi, la ricerca di tutti i collegamenti con un nome descrittivo specifico (usando FindAll, ad esempio) restituirà più risultati. Sarà quindi necessario esaminare l'origine di ogni collegamento per determinare la cartella contenitore e quindi determinare quale collegamento fa riferimento all'elemento desiderato.

È necessario un modo per fare riferimento a qualsiasi elemento arbitrario nel negozio, ad esempio, si supponga di volere il 3.287° elemento nel negozio. Fortunatamente, puoi fare esattamente questo.

Ricerca di un elemento in base al valore ItemID_Key

WinFS assegna a ogni elemento appena creato un numero di identificazione basato su GUID, noto come proprietà ItemID_Key. In pratica, un valore ItemID_Key è altamente probabile che sia univoco in tutti i volumi WinFS; Tuttavia, WinFS considera comunque questo identificatore come se fosse univoco solo all'interno di un volume. È possibile usare questo valore univoco del volume per identificare qualsiasi elemento in un volume 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);
}

Funzionalità comuni

L'API WinFS offre diverse funzionalità nell'intero spettro delle classi di dati. Queste funzionalità sono

  • Asincronia
  • Transazioni
  • Notifiche
  • Supporto blob/flusso
  • Cursore e paging

Asincronia

L'API WinFS consente di eseguire query in modo asincrono. L'API WinFS usa i modelli di modello di programmazione asincrona standard .NET.

Transazioni

L'archivio WinFS è un archivio transazionale. WinFS, pertanto, consente di eseguire aggiornamenti transazionali all'archivio usando i metodi BeginTransaction, CommitTransactione AbortTransaction sull'oggetto ItemContext, come illustrato nell'esempio seguente:

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 ();
  }
}

Notifiche

Il servizio di notifica WinFS usa i concetti delle sottoscrizioni a breve termine e a lungo termine. Una sottoscrizione a breve termine dura fino a quando un'applicazione non annulla la sottoscrizione o l'applicazione viene chiusa. Una sottoscrizione a lungo termine sopravvive ai riavvii dell'applicazione. L'API WinFS watcher sono un set di classi che consentono alle applicazioni di ricevere una notifica selettiva delle modifiche nell'archivio WinFS e forniscono informazioni sullo stato che possono essere mantenute dall'applicazione per supportare scenari di sospensione/ripresa.

La classe Watcher può notificare all'applicazione modifiche a diversi aspetti degli oggetti WinFS, tra cui:

  • Modifiche degli elementi
  • Modifiche degli elementi incorporati
  • Modifiche all'estensione dell'elemento
  • Modifiche alle relazioni

Quando un watcher genera un evento, invia i dati sullo stato del watcher con la notifica dell'evento. L'applicazione può archiviare questi dati di stato per il recupero successivo. Successivamente, puoi usare questi dati sullo stato watcher per indicare a WinFS che vuoi ricevere eventi per tutte le modifiche che si sono verificate dopo la generazione dello stato.

Il modello di programmazione watcher consente anche di disabilitare qualsiasi combinazione di eventi aggiunti, modificati e rimossi. Può anche essere configurato per generare un evento iniziale che simula l'aggiunta di tutti gli elementi, le estensioni degli elementi, le relazioni e così via.

La progettazione del watcher WinFS è suddivisa nelle classi descritte nella tabella seguente.

Classe Scopo/Descrizione
WatcherOptions Classe per specificare l'ambito iniziale e le opzioni di granularità per StoreWatcher
StoreWatcher La classe quintessenti per la visualizzazione di elementi WinFS, elementi incorporati, estensioni di elementi e relazioni
WatcherState Oggetto opaco che può essere utilizzato per inizializzare un StoreWatcher
ChangedEventHandler Classe che definisce il gestore eventi da chiamare da StoreWatcher
ChangedEventArgs Classe passata come argomento a ChangedEventHandler
ItemChangeDetail Classe base che fornisce dettagli granulari sulle modifiche per gli eventi degli elementi
ItemExtensionChangeDetail Classe derivata da ItemChangeDetail che fornisce dettagli di modifica aggiuntivi specifici per gli eventi di estensione degli elementi
RelationshipChangeDetail Classe derivata da ItemChangeDetail che fornisce dettagli di modifica aggiuntivi specifici per gli eventi di relazione

Si usa la classe StoreWatcher per creare un watcher per alcuni elementi nell'archivio WinFS. L'istanza di StoreWatcher genererà eventi quando l'elemento specificato cambia. È possibile specificare il tipo di elemento e gerarchia da controllare. Per impostazione predefinita, un watcher

  • Non genera un evento iniziale per stabilire lo stato corrente
  • Controlla l'elemento e la gerarchia (inclusi gli elementi figlio immediati) per eventuali modifiche
  • Genera eventi di aggiunta, rimozione e modifica in questo elemento o in qualsiasi elemento figlio nell'intera gerarchia
  • Genera eventi di aggiunta, rimozione e modifica per le estensioni degli elementi in questo elemento o in qualsiasi elemento figlio nell'intera gerarchia
  • Genera eventi di aggiunta, rimozione e modifica per le relazioni in cui questo elemento o qualsiasi elemento figlio nell'intera gerarchia è l'origine della relazione

Poiché per impostazione predefinita un watcher controlla le modifiche apportate all'elemento specificato e ai relativi discendenti, è possibile specificare WatchItemOnly come opzione watcher. L'esempio seguente controlla solo le modifiche apportate all'elemento Person individuato:

Person p = Person.FindOne (ctx,
            "PersonalNames[GivenName='Rachel' and Surname='Emerald'");
StoreWatcher w = new StoreWatcher ( p, WatcherOptions.WatchItemOnly );

Una cartella è solo un altro elemento WinFS. Si osservano le modifiche in una cartella nello stesso modo in cui si esegue per una persona:

Folder f = · · ·
StoreWatcher w = new StoreWatcher (f, <WatcherOptions>);

È possibile controllare le modifiche in una relazione specificata di un elemento, anche:

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;
  }
}

Supporto blob e flusso

Le API di supporto per BLOB e flussi sono ancora in flusso al momento della stesura di questo articolo. Consultare la documentazione per le informazioni più recenti su come accedere a BLOB e flussi nell'archivio WinFS.

Cursore e paging

I vari metodi Find nelle classi WinFS possono restituire una raccolta di oggetti (potenzialmente) di grandi dimensioni. Questa raccolta è l'equivalente di un set di righe nel mondo del database. Le applicazioni di database tradizionali usano un cursore di paging per spostarsi in modo efficiente all'interno di un set di righe di grandi dimensioni. Questo cursore fa riferimento a una singola riga (cursoresottile) o a un set di righe (una pagina cursore). L'idea è che le applicazioni recuperino una pagina di righe alla volta; possono anche individuare una riga all'interno della pagina per l'aggiornamento e l'eliminazione posizionati. L'API WinFS fornisce astrazioni simili allo sviluppatore per gestire raccolte di grandi dimensioni.

Per impostazione predefinita, un'operazione di ricerca fornisce un cursore dinamico di sola lettura, scorrevole e dinamico sulla raccolta restituita. Un'applicazione può avere un cursore del tubo di fuoco per ottenere prestazioni massime. Un cursore del tubo di fuoco è un cursore forward-only. L'applicazione può recuperare una pagina di righe alla volta, ma l'operazione di recupero successiva inizierà con il set successivo di righe, ma non può tornare indietro e recuperare nuovamente le righe. In un certo senso, le righe passano dal negozio all'applicazione come acqua da un tubo di fuoco, quindi il nome.

La proprietà CursorType nella classe FindParameters consentirà a un'applicazione di scegliere tra un tubo di fuoco e un cursore scorrevole. Sia per il tubo di fuoco che per i cursori scorrevoli, l'applicazione può impostare una dimensione di pagina usando la proprietà PageSize della classe FindParameters. Per impostazione predefinita, le dimensioni della pagina sono impostate su 1.

Data Binding

È possibile usare le classi di dati WinFS come origini dati in un ambiente di data binding. Le classi WinFS implementano IDataEntity (per singoli oggetti) e interfacce di IDataCollection (per le raccolte). L'interfaccia IDataEntity fornisce notifiche alla destinazione di data binding delle modifiche alle proprietà nell'oggetto origine dati. L'interfaccia IDataCollection consente la determinazione del tipo di base di un oggetto in una raccolta polimorfica. Consente inoltre di recuperare un System.Windows.Data.CollectionManager, che consente di spostarsi tra le entità dati della raccolta e di fornire una visualizzazione (ad esempio, l'ordinamento o il filtro) della raccolta. Il data binding viene illustrato in dettaglio nel capitolo 5.

Sicurezza

Il modello di sicurezza WinFS concede fondamentalmente un set di Rights a un Principal in un Item nei modi seguenti:

  • La sicurezza viene impostata a livello di Items.
  • È possibile concedere un set di diritti a un principio di sicurezza in un Item. Questo set include: READ, WRITE, DELETE, EXECUTE (per tutti gli elementi), CREATE_CHILD, ADMINISTER e AUDIT. (Sono consentiti diritti aggiuntivi per gli elementi della cartella).
  • Gli utenti e le applicazioni sono i principi di sicurezza. I diritti dell'applicazione sostituisce i diritti utente. Quando un'applicazione non dispone dell'autorizzazione per eliminare un contatto, un utente non può eliminarlo tramite l'applicazione indipendentemente dalle autorizzazioni dell'utente.
  • La sicurezza viene impostata usando le regole; ogni regola è un Grant e si applica a un tripletto: (<ItemSet, PrincipalSet, RightSet>).
  • Le regole vengono archiviate come Items.

Ottenere diritti per un elemento

Ogni classe di elemento WinFS ha un metodo denominato GetRightsForCurrentUser, che restituisce il set di diritti( READ, WRITE, DELETE e così via) che l'utente corrente ha sull'elemento specificato. Inoltre, il metodo restituisce il set di metodi che WinFS consente all'utente di eseguire.

Impostazione dei diritti per un elemento

WinFS usa un tipo di elemento speciale, SecurityRule, per archiviare le informazioni sulle autorizzazioni per Items. Pertanto, l'impostazione e la modifica dei diritti non è diversa dalla modifica di qualsiasi altra Item in WinFS. Ecco un esempio di codice che illustra come impostare i diritti per un elemento di cartella:

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();
}

Estensione dell'API WinFS

Ogni classe WinFS predefinita contiene metodi standard, ad esempio Find* e ha proprietà per ottenere e impostare i valori dei campi. Queste classi e i metodi associati costituiscono la base delle API WinFS e consentono di imparare a usare una classe e sapere, in generale, come usare molte altre classi WinFS. Tuttavia, mentre il comportamento standard è utile, ogni tipo di dati specifico richiede comportamenti aggiuntivi specifici del tipo.

Comportamenti del dominio

Oltre a questi metodi standard, ogni tipo WinFS in genere avrà un set di metodi specifici del dominio univoci per quel tipo. In realtà, la documentazione di WinFS spesso si riferisce alle definizioni dei tipi come schema, riflettendo il patrimonio del database di WinFS. WinFS fa riferimento a questi metodi specifici del tipo come comportamenti di dominio . Ecco ad esempio alcuni comportamenti del dominio nello schema dei contatti:

  • Determinare se un indirizzo di posta elettronica è valido
  • Data una cartella, recupero della raccolta di tutti i membri della cartella
  • Dato un ID elemento, recupero di un oggetto che rappresenta questo elemento
  • Data una persona, ottenere il suo stato online
  • Creazione di un nuovo contatto o di un contatto temporaneo con funzioni helper

Value-Added comportamenti

Le classi di dati con comportamenti di dominio costituiscono una base su cui gli sviluppatori di applicazioni si basano. Tuttavia, non è possibile né auspicabile per le classi di dati esporre ogni comportamento concepibile correlato a tali dati.

È possibile fornire nuove classi che estendono le funzionalità di base offerte dalle classi di dati WinFS. A tale scopo, scrivere una classe i cui metodi accettano una o più classi di dati WinFS come parametri. Nell'esempio seguente le classi OutlookMainServices e WindowsMessageServices sono classi ipotetiche che usano le classi MailMessage e Person WinFS standard:

MailMessage m = MailMessage.FindOne (…);
OutlookEMailServices.SendMessage(m); 
 
Person p = Person.FindOne (…);
WindowsMessagerServices wms = new WindowsMessagerServices(p);
wms.MessageReceived += new MessageReceivedHandler (OnMessageReceived);
wms.SendMessage("Hello");

È quindi possibile registrare queste classi personalizzate con WinFS. I dati di registrazione verranno associati ai metadati dello schema gestiti da WinFS per ogni tipo WinFS installato. WinFS archivia i metadati dello schema come elementi WinFS; pertanto, è possibile aggiornare, eseguire query e recuperarlo come tutti gli altri elementi WinFS.

Specifica dei vincoli

Il modello di dati WinFS consente vincoli di valore sui tipi. WinFS valuta e applica questi vincoli quando si aggiungono elementi all'archivio. Tuttavia, a volte si vuole verificare che i dati di input soddisfino i relativi vincoli senza incorrere nell'overhead di un round trip al server. WinFS consente all'autore dello schema/tipo di decidere se il tipo supporta il controllo dei vincoli lato client. Quando un tipo supporta la convalida lato client, il tipo avrà un metodo validate che è possibile chiamare per verificare che un oggetto soddisfi i vincoli specificati. Si noti che, indipendentemente dal fatto che lo sviluppatore chiami il metodo Validate, WinFS controlla comunque i vincoli nell'archivio.

Uso dell'API WinFS e di SQL

L'API WinFS consente a uno sviluppatore di accedere all'archivio WinFS usando concetti comuni di Common Language Runtime (CLR). In questo capitolo ho usato il modello di codifica seguente per l'accesso a WinFS:

  1. Eseguire l'associazione a un ItemContext.
  2. Trovare gli elementi desiderati.
  3. Aggiornare gli elementi.
  4. Salvare tutte le modifiche apportate all'archivio.

Il passaggio 2 è essenzialmente una query nell'archivio. L'API WinFS usa una sintassi dell'espressione di filtro basata su OPath per specificare queste query. In molti casi, l'uso delle espressioni di filtro deve essere sufficiente per la maggior parte delle attività. Tuttavia, ci saranno casi in cui lo sviluppatore vuole usare tutta la potenza e la flessibilità di SQL.

In SQL sono presenti le funzionalità seguenti, ma non sono disponibili quando si usa un'espressione di filtro:

  • Aggregazione (Group By, Having, Rollup)
  • Proiezione (incluse espressioni select calcolate, distinct, IdentityCol, RowGuidCol)
  • Per XML
  • Unione
  • Opzione
  • Right/full/cross join
  • Selezioni annidate
  • Join a una tabella non WinFS

È quindi essenziale che uno sviluppatore WinFS sia in grado di eseguire facilmente la transizione tra l'API SQLClient e l'API WinFS, usando una o l'altra in varie posizioni nel codice.

Aggregare e raggruppare con SQL e quindi usare l'API WinFS

Un piccolo imprenditore, Joe, vuole determinare chi sono i suoi primi 10 clienti e inviare cestini regalo a loro. Si supponga che Customer sia un tipo di elemento schematizzato. Ciò significa che un ISV ha fornito uno schema per il tipo di cliente a WinFS, quindi significa anche che un archivio WinFS può ora contenere elementi del cliente. Un elemento Customer ha un collegamento che contiene un collegamento a un tipo di elemento dell'ordine schematizzato. Order Item include una raccolta incorporata di Line Orders, come indicato di seguito:

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. }                                             

Nella riga 1 di questo esempio si apre un contesto per la radice del volume di sistema. Nella riga 3 viene creato un oggetto comando SQL che successivamente si usa per eseguire una query SQL sull'archivio WinFS. Questo oggetto comando riutilizza la connessione utilizzata dal contesto dell'elemento. Le righe da 4 a 12 costruiscono la query e la riga 14 esegue la query. La query restituisce i primi 10 clienti nel modo seguente: l'istruzione SELECT nelle righe da 6 a 12 genera una tabella raggruppata contenente il valore totale degli ordini di ogni cliente; la clausola ORDER BY nella riga 12, combinata con il modificatore TOP 10 nella riga 6, seleziona solo i primi 10 clienti in questa tabella raggruppata.

La classe GiftBasketOrder è una classe personalizzata che usa l'oggetto Customer API WinFS. Creare un'istanza di GiftBasketOrder alla riga 16.

La riga 19 usa il SQLDataReader per leggere la prima colonna del set di righe restituito e la esegue il cast in un oggetto CustomerData.

Quando definisci un nuovo tipo in WinFS (noto come creazione di un nuovo schema), definisci effettivamente due tipi: la classe gestita e il formato permanente dell'archivio WinFS della classe. WinFS aggiunge sempre il suffisso Data al nome della classe per creare il nome del tipo dell'archivio. Pertanto, quando definisci un nuovo tipo di cliente che risiede nell'archivio WinFS, WinFS crea il CustomerData tipo definito dall'utente WinFS in parallelo.

La prima colonna del set di righe contiene l'oggetto CustomerData dell'archivio. Questo oggetto viene passato al costruttore della classe Customer e il costruttore inizializza il nuovo oggetto dall'oggetto CustomerData. Questo esempio è tipico dell'uso dei tipi definiti dall'utente di archiviazione per costruire oggetti API WinFS.

La riga 24 aggiunge il cliente alla raccolta Recipients del GiftBasketOrder.

Infine, uso il metodo Send su gbOrder per "inviare" questo ordine.

Si supponga di voler trovare lo stipendio medio (in un periodo di 10 anni) per il CEO di ogni società nel mio portafoglio. Usare i presupposti seguenti:

  • Ho una cartella denominata Companies In My Portfolio, che contiene elementi di tipo Organization.
  • EmployeeData è una relazione di collegamento e ha un YearlyEmploymentHistory che ha l'anno e lo stipendio per quell'anno.
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. }

La riga 1 apre un contesto per la condivisione Company In My Portfolio WinFS. Le righe da 3 a 11 creano una query SQL con parametri che è possibile usare nel contesto della cartella. Questa query restituisce lo stipendio medio per un determinato dipendente (rappresentato dal parametro @LinkID). Le righe 10 e 11 specificano che @LinkID è un parametro di tipo BigInt. Questa query viene eseguita più avanti nell'esempio alla riga 20.

La riga 13 ottiene un oggetto Folder che rappresenta la cartella indicata dalla condivisione specificata durante la creazione del contesto. Le righe 15 e 16 configurano il ciclo per scorrere l'insieme di oggetti Organization in questa cartella.

Per ogni organizzazione, la riga 17 ottiene l'oggetto EmployeeData per il CEO.

La riga 19 prepara per la query e imposta il valore del parametro sul LinkID appropriato, quindi la riga 20 esegue l'istruzione SELECT con parametri.

La riga 21 legge la riga successiva e solo dal risultato della query e le righe 22 e 23 stampano il nome del CEO e lo stipendio medio di 10 anni.

Sommario

L'archivio dati WinFS offre un modello di archiviazione dei dati molto più completo rispetto ai file system tradizionali. Poiché supporta dati, comportamento e relazioni, è difficile classificare WinFS come file system, un database relazionale o un database oggetto. È un po' tutte queste tecnologie in un unico prodotto. WinFS fornisce una definizione comune di informazioni onnipresenti visibili a livello globale e disponibili per tutte le applicazioni in esecuzione su Longhorn. Le applicazioni possono sfruttare le funzionalità di query, recupero, aggiornamento transazionale e filtro di WinFS; pertanto, lo sviluppatore impiega meno tempo a sviluppare l'accesso ai dati e il codice di archiviazione e più tempo a lavorare su funzionalità specifiche dell'applicazione.

continuare con il capitolo 5: data binding