The recent posts about WinFS using OPath (which is correct) and about the use of properties vs. methods in an API juxtapose in an interesting way in the WinFS API. Basically OPath lets me write a boolean expression using the properties exposed by a class. OPath doesn't let you use methods in the expression because OPath is actually converted to a SQL query and executed in the database.
In the WinFS API we have a Relationship class. The Relationship type in WinFS has two properties: source item id and target item id. When writing an OPath expression, we want you to be able to navigate from an item through relationships to the source or target item. To make this easy, we want to expose properties that represent the source and item target object's themselves. For example, to find all the people who live in the New York metropolitan region, you would write code like the following:
Person.FindAll(“IncomingRelationships.Cast(System.Storage.Contacts.HouseholdMember).Household.OutgoingRelationships.Cast(System.Storage.Core.ContactLocations).Location.MetropolitanRegion = ‘New York’“ );
Follow along in the diagram below. Start with the Person items. IncomingRelationships.Cast(...HouseholdMember) gets you to the HouseholdMembership relationships that target all Person items. Household is a property that gets you to the Household item that is the source of the relationship. OutgoingRelationships.Cast(...ContactLocations) gets you to ContactLocation relationships. Location gets you to Location items. The Location items have a MetropolitanRegion property which is compared to the string 'New York'.
Now, here is the dilemma: we added Source and Target properties to Relationship to make writing a query easy, but actually providing a value for these properties may require a round trip to the store (it can take a while and fail in unexpected ways). In the query this is fine (we actually ask the store to do a join based on the item ids). For example:
foreach( HouseholdMember hm in HouseholdMember )
Person p = hm.Person; // could take some time
Houeshold h = hm.Household; // could take some time
It is the property vs. method debate, but with the twist that we want some things to be properties so they can be used in a query.