An Opinion blog

My Links

Story Categories


Post Categories

Image Galleries




This site is operated by Mike Deem. The opinions expressed here are mine. They are not necessarily my employer's or anybody else's.

Friday, November 21, 2003 #

Properties vs. Methods Take Two

In a private e-mail, Brad Abrams ask me to clarify the property vs. method issue in the WinFS API. I put together this hopefully simplified explanation. What follows is essentially a conceptual description, I’m glossing over a lot of details and the attributes shown aren’t exactly the ones we use.

In WinFS we have an item table and a relationship table. The item table has an ItemId column. The relationship table has SourceItemId and TargetItemId columns. At the SQL level, when querying for related items you join through the relationship table.

When mapping items and relationships to objects we end up with something like the classes shown below. This lets use properties in the classes to represent the joins.

public class Relationship

  public ItemId SourceItemId { get; } 
  public ItemId TargetItemId { get; } 

  [Join(“SourceItemId”, “Item.ItemId”)] 
  public Item Source { get; } 

  [Join(“TargetItemId”, “Item.ItemId”)] 
  public Item Target { get; }

public class Item

  public ItemId { get; } 

  string DisplayName { get; set; } 

  [Join(“ItemId“, “Relationship.SourceItemId“)] 
  public VirtualRelationshipCollection OutgoingRelationships { get; } 

  [Join(“ItemId“, “Relationship.TargetItemId”)] 
  public VirtualRelationshipCollection IncommingRelationships { get; }


These properties show up in two places: in applications which use them to “navigate” from object to object in memory and in queries that traverse the joins between the underlying tables. Let’s look at the query case. If I want to find all items targeted by a relationship from any item with the display name “foo”, I can use the following code:

foreach( Item item in Item.FindAll( “IncommingRelationships.Source.DisplayName=’foo’” ) ) ...;

What this does is cause us to generate a query against the item table that joins to the relationship table using Item.ItemId = Relationship.TargetItemId and then back to the Item table using Relationship.SourceItemId = Item.ItemId.

Now, it is very common for an item to be related to many other items. Hence we use our VirtualRelationshipCollection type to represent the relationships in the Item class. This type doesn’t load all the relationship objects when the item object is loaded. They are not even loaded when the application accesses the property, as they can be used for Add and Remove operations without loading all relationships into memory. The relationships are loaded only if the application tries to enumerate over the collection.

Similarly, there are scenarios where an application may want work with a relationship object without actually loading the source and/or target item object into memory. The source/target object is loaded only when the Source/Target property is first accessed.

We could use GetSource and GetTarget methods insted of properties in the Relationship class, but what should we then do in OPath? One of the goals of OPath is to allow queries to exactly mirror the object models. If we use GetSource in the object, the OPath should become “IncommingRelationships.GetSrouce().DisplayName”. The problem is, in general, we cannot let you use the methods on a class in OPath.

The principle we are trying to follow in the WinFS API is: if you see a property in the object browser, you can use that property in your OPath but you can’t use any methods in OPath. We have gone out of our way to make things you can’t use in queries accessible only by calling methods.

So we have conflicting requirements: using properties/methods to convey to the user what can and cannot be accessed efficiently and with minimal chance of failure vs. using properties/methods to convey to the user what they can and cannot use in OPath. Given that the former is the established rule, it should take precedence. However, that leaves us with the problem of trying to identify what can be used in OPath.

Maybe the current situation isn’t so bad. The Source and Target properties in relationship classes are the only ones that are loaded on first access. There are no other properties in all of the WinFS API like this. Similarly, the number of places we used methods instead of properties because a value cannot be used in OPath is also limited.

posted @ 5:21 PM | Feedback (5)