WinFS Basics: Working with a Data Store

WinFS is probably one of the most exciting offerings in the Microsoft pipeline. The next step in information storage on the Windows platform, WinFS is an active storage platform based on a data model that is an organizational framework of WinFS Types. Some of the out-of-the-box types in WinFS are Document, Contact, Picture, VideoRecord, and so forth. You also can extend the built-in type system by creating your own types, which makes the type model extensible. And, because it enables you to represent your data as objects, you can have synchronization and rules capabilities built right into the framework that supports them.

Conceptually, WinFS is structured very much like the world around us. When I think of my head, for example, I see an information storage and retrieval machine with various objects in it: people, books, cities—distinct entities that work independently and yet are somehow loosely related to each other. I also see various behaviors and interrelationships between these various objects. As another example, consider the persons at Microsoft who author the fantastic WinFS blog in Redmond. This example contains three distinct EntityTypes: "Persons," "Blog," and "City." You can examine two of these more closely:

  • "Persons" theoretically are "Employees of Microsoft," which is an ordered, unsorted array of "Employee of Microsoft," which inherits from "Intelligent Person," which itself inherits from "Human Being."
  • "City" could have a latitude, longitude, population—it even has a City name, and it's related to yet another EntityType called "State" (Redmond is in Washington State).

So, if all this information were represented in a computing environment, you'd typically represent them in objects or, more specifically, semistructured hierarchical object structures. That's a mouthful, but conceptually the world is full of semistructured hierarchical objects. (My head is full of them, in fact.) The problem is historically we have tried to store all this information in file systems, which let you store only flat files with almost no relationships between them. Clearly, that needs to evolve, and WinFS is part of that growth.

No single article can cover all WinFS that offers, but this article explains how to work with a main WinFS feature: the data store. It then demonstrates the basic operations that you can perform on a WinFS data store.

A WinFS Data Store

A traditional file system stores information in a directory structure. In addition to being a file system, WinFS offers the capability of storing your various items (object instances) in item data stores, which WinFS stores in a relational backend. Giving data an object or item representation instills behavior in your flat files.

At the same time, because WinFS also comes with a new file system driver (RsFxDrv.sys), a WinFS item is also made available as a file-backed item. This allows you to access a WinFS item both as a file stream through the Win32 API or as an item via the WinFS API. The two representations of the item—file based and item based—are kept in synch using the WinFS Infrastructure. The synch process consists of two distinct steps:

  1. Extracting data from a file and populating an item (also known as promotion)
  2. Persisting itemized data to streams of the underlying file (also known as demotion)

This allows WinFS to be backwards compatible with both NTFS- and FAT-based file systems. This means the user never knows whether he or she is working on WinFS or just NTFS because the change is seamless. You get the extra capabilities of the new file system while being fully backwards compatible.

Organizing Your Data

Historically, file and folder structures give you a rather strict and limited method of organizing your data; a file is contained within a folder. This model doesn't explain the richness of your data. For example, the ring that you just bought for your fiancée could be sitting under \Finance\Bills\CreditCard and also under \Family\UndyingLove. In addition to being able to store your data in a much richer logical structure, you can also assign keywords to your objects in WinFS as follows:

ItemKeywords keywords = new ItemKeywords();
keywords.Keywords.Add(new Keyword("Diamonds"));
ringDocument.Extensions.Add(keywords);

Once you have your data properly tagged, you can search it as follows:

StorageSearcher<Document> docs =
   wd.Items.FilterByType<Document>().
   Filter("Exists(Extensions.FilterByType(@0).
   Filter(Exists(Keywords.Filter(Value==@1))))",
   typeof(ItemKeywords), "Diamonds");

foreach (Document doc in docs)
{
    Console.WriteLine("Doc's Title = {0}", doc.Title);
}

Not only can you add keywords to existing documents, but a given document may also have the capability of exposing such metadata about itself, making itself easily searchable. For instance, if you author a Microsoft Word document, it is automatically promoted to an instance of System.Storage.Documents.Document, which then automatically populates its various relevant properties such as title, subtitle, author, and so forth.

So, what is the big deal? The big deal is that if you were to search for "Diamonds," you would not only get the ring you bought in one of the results, you would also get the Word document that stores the history of the transaction, the PDF download that holds your credit card transaction information, all e-mails between you and the jeweler, and all other such relevant information. Also, now you could easily establish further relationships between various items in your WinFS data stores. You can turn these items into active data by associating them with rules.

Working with WinFS Data Using the WinFS API

The WinFS .NET object-based API consists of various classes that can be divided into two main groups: the data, and what lets you work with the data. Let me begin with data. Figure 1 shows a data class in WinFS, also known as Entity class, which is one among four others: Item, ItemFragment, ItemExtension, and Link.

Figure 1. Organization of Major WinFS Data-Related Classes

An Item is what you will be dealing with most frequently. This is the semistructured object structure that you identify with when you think of unique entities in your data. So, you can think of a document as an item inherited from the Item class. Similarly, a message would be an item. A folder, a contact, an attachment, a video file, an audio file, and so on would also be items.

An ItemFragment enables the declaration of large collections in item types. For instance, a message may have a number of participants, each represented by an instance of Participant. In this scenario, Participants would be a property on the Message Item of data type ItemFragmentCollection<Participant>, where Participant would inherit from ItemFragment. Also, because ItemFragment is yet another entity that simply lives as data in a WinFS store, it also inherits from Entity.

An EntityExtension is what would allow you to extend built-in items by adding further properties as necessary. As you may expect, this property is defined in the Item abstract class, so every WinFS Item has this property exposed as the Extension property, which is of data type ItemExtensionCollection. This is what lets you "tag" your data with words. Examine keyword assignments to your objects once more to set things in place:

ItemKeywords keywords = new ItemKeywords();
keywords.Keywords.Add(new Keyword("Diamonds"));
ringDocument.Extensions.Add(keywords);

Finally, Link is also data, but it is data that defines links between two or more distinct existing item types. So, a Message may have attachments that are documents.

Classes for Working with WinFS Data Stores

Now that you have data squared away, you also need classes to work with the WinFS data stores. Many WinFS framework classes will help you work with WinFS data stores. Besides the two namespaces dedicated exclusively to WinFS Sync and WinFS Rules (namely, System.Storage.Sync and System.Storage.Rules), you will frequently deal with StorageContext, StorageSearcher, and StorageWatcher classes.

StorageContext is what allows you to connect to a WinFS data store. StorageSearcher performs searches and holds a result set. You already saw usage of this class in the following data search code:

StorageSearcher<Document> docs =
   wd.Items.FilterByType<Document>().
   Filter("Exists(Extensions.FilterByType(@0).
   Filter(Exists(Keywords.Filter(Value==@1))))",
   typeof(ItemKeywords), "Diamonds");

foreach (Document doc in docs)
{
    Console.WriteLine("Doc's Title = {0}", doc.Title);
}

As you can see, the WinFS API supports an object path query language that allows you to specify filter criteria in your queries.

StorageWatcher monitors for various events or data change notifications on a WinFS data store.

Putting all these together, you could easily add a folder called "WinFS article folder" and add one item in it called Maliks, which is of type System.Storage.Contacts.Contact, by writing the following code:

using (WinFSData wfsDat = new WinFSData())
{
   Folder newFolder = new Folder();
   newFolder.DisplayName = "WinFS article folder";
   newFolder.NamespaceName = "WinFS article folder";
   newFolder.Container = wfsDat.GetRootItem();

   Contact sahil = new Contact(newFolder);
   sahil.DisplayName = "Sahil Malik";
   sahil.NamespaceName = "Maliks";
   ContactCard sahilCard = new ContactCard();
   sahilCard.EAddresses.Add(
      new System.Storage.Core.EAddress("smalik@nospam.com"));
   sahil.ContactCards.Add(sahilCard);
   wfsDat.SaveChanges();
}

Figure 2 shows the results of the above code.

Figure 2. Adding a Folder and an Item

Now that you have a data store populated, you could use the following code to query it:

using (WinFSData wfsDat =
   new WinFSData(@"\\HOMEPCOLD\DefaultStore\WinFS article folder"))
{
   StorageSearcher<Contact> contacts =
      wfsDat.Items.FilterByType<Contact>();
   foreach (Contact c in contacts)
   {
      Console.WriteLine("Display Name: " + c.DisplayName);
   }
}

This code should produce the output in Figure 3.

Figure 3. Query Your Data Store

Interestingly, if you accessed the file backend with the Win32 API using the following VBScript:

filePath="\\HOMEPCOLD\DefaultStore\WinFS article folder"
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.GetFolder(filePath)
msgbox f.Name

It should produce the following output:

If you instead browsed to a text document stored in a WinFS data store, you would be able to read its contents using a simple text stream—just as you would read off of your C:\ drive.

The Basics of WinFS

WinFS is a large topic that cannot be covered in a single article, but you now know the basics of working with a data store. WinFS has other exciting facets, such as being able to author your own types, WinFS rules, and WinFS Sync, which make WinFS one of the most exciting offers on the horizon.

About the Author

Sahil Malik has worked for a number of top-notch clients in Microsoft technologies ranging from DOS to .NET. He is the author of Pro ADO.NET 2.0 and co-author of Pro ADO.NET with VB.NET 1.1. Sahil is currently also working on a multimedia series on ADO.NET 2.0 for Keystone Learning. For his community involvement, contributions, and speaking, he has also been awarded the Microsoft MVP award.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds