View Class Definition

Hide Navigation Pane

View Class Definition

Previous topic Next topic No directory for this topic  

View Class Definition

Previous topic Next topic Topic directory requires JavaScript JavaScript is required for the print function Mail us feedback on this topic!  

A view class is analogous to a database query, but operates on the fully connected persistent tree, rather than disparate tables in a SQL database.  In some ways it can be seen as a managed query, where the joins are type safe.  In a view class, in place of joining tables on matching keys, you traverse the persistent tree from a known root object to the members you want to include in the view, using the links already in place, as created in your package definition file.

Persistate creates a .Net class for the view classes you write in your definition file.  These .Net classes are used to hold the results of selections made using the view class.  You must also include a selected collection member with the view class  type in the object class which you define as the view parent.  This collection receives the selections you make with your view class.  Here is an example view class.

Every monthly lend statistic in the library consolidated by
   its lends publication if book genre
   the genre name in first order,
   a lend count = count of its lends
   its lends borrowed > parameter from and
   its lends borrowed < parameter to

This defines a view class called monthly lend statistic with the library class as view parent.  You must then create the collection to receive it in the library class as follows.  In this case the class is a singleton, but it doesn't have to be.

The library is a stable persistent containing
   . . .
   selected monthly lend statistics,
   . . .

With these definitions, Persistate will generate a .Net class called MonthlyLendStatistic to receive selected data, and this will have properties Name and LendCount.  In the generated .Net Library class, Persistate will create a MonthlyLendStatistics collection, and a method called SelectMonthlyLendStatistics.  This will have two DateTime parameters from and to where you supply values for the two parameters defined above in the view class.


You traverse the persistent tree in several places when defining a view class.

You traverse from the view parent class to each node you want to use as a base.  The results of the selection are consolidated by the bases you define, in the above example, results are consolidated by genre, the traverse being its lends publication if book genre.
You traverse from the view parent class, or from any defined base, to each node you want to include as a view member, or as the subject of an aggregate.  In the above example, the traverses are the genre name and its lends.
You traverse from the view parent class, or from any defined base, to nodes you want to use as the left hand side of a condition.  In the above example, the traverse its lends borrowed is used for this twice.

To write a traverse, you set a starting point, and then move though the persistent tree node by node to reach an end point.  Starting points can either be the view parent class, set by the word its, or any of the defined bases, set by the word the followed by the name of the end point node of the base traverse, genre in the above example.  In base traverses, only its is allowed as a starting point.

The nodes you traverse through are all object classes, except for end point nodes which can also can be data classes   There are a number of 'moves' you can make while traversing.

Move to a member.  If the current node is an object class, just write a member name to move to the class of that member.  The member can be from the actual class of the node, or any of its base classes, can be contained or associated, and can be scalar or a collection.  If the member has a data class, then you can move no further, and the member must be your end point.  If the member has an object class, then that is now your current node and you can continue.
Move to the parent class.  To do this, just write the word parent.  The new node is the parent object class of the current node.  You can only use this move if the object class of the current node has a parent class in its definition.
Move to a derived class of the current node's object class.  To do this, write the word if followed by the name of the derived class.  The new current node is the derived object class.


So far, the above discussion has talked about traversing from object class to object class and possibly to data class at end points.  This traversing defines the end points of the bases, view members and condition left hand sides, and exists in the metadata domain of object classes and members.  When you perform a selection by calling the view class's generated selection method, then the same traverses are applied to the instance domain.

On selection, the parent object class is notionally replaced with the instance of it that the selection method is called on.   This is the root object, and is the start point for traverses, which now traverse instances rather than classes. Every move in a traverse that goes to a collection node causes the number of traverses to be multiplied by the number of objects in that collection.  This happens for every move to a collection node in the view class, resulting in potentially a large number of traverses, and therefore resulting instances of the view class objects.

There are two mitigating factors though.  The first is the set of bases that you define for the view class.  When you create a base, you are essentially collapsing any multiplication of any traverse from the root that goes beyond the base endpoint.  Bases also similarly collapse traverse multiplication root-ward of the base end point if there is a collection to scalar move in the base traverse.  The second mitigating factor is the set of conditions that you apply.  These can halt a traverse at any point that a node value fails the condition.

Of course, all of this is really just a different spin on how SQL queries perform, and indeed Persistate creates SQL queries to perform the selection.  The important point about view classes, though, is the one made at the top of this topic, and that is that in a view class there is no mention of keys or joins.  These are replaced with the inter-class links already defined by the persistent tree structure created by the package's object class definitions.  This of course results in a loss of flexibility, but that is the price to be paid when moving from an unmanaged to a managed environment.

Future Enhancement

View classes in the current version of Persistate are very much provisional.  Options for future development include dispensing with the generated view class if there is a single object class view member, more options for data consolidation, implementing pivot filters, and more extensive options for data mining.


ViewClass = "every" ViewClassName ( "of" | "in" ) ( "a" | "an" | "the" ) ViewParentName 
            [ "consolidated" "by" Bases ] "contains" ViewMember { "," ViewMember } 
            [ "where" CompoundCondition ] ;
ViewClassName = <symbol> { <symbol> } ;
ViewParentName = <symbol> { <symbol> } ;
Bases = Traverse { "," Traverse } ;
Traverse = <symbol> { <symbol> } ;
ViewMember = [ ( "a" | "an" ) ViewMemberName "=" ] [ Aggregate "of" ] Traverse 
             [ "with" SimpleCondition ] [ "in" Ordinal "order" ] ;
ViewMemberName = <symbol> { <symbol> } ;
Aggregate = ( "count" | "mean" | "sum" | "minimum" | "maximum" | "deviation" | "variance" ) ;
Ordinal = ( "first" | "second" | "third" | "fourth" | "fifth" 
          | "sixth" | "seventh" | "eighth" | "ninth" | "tenth" ) ;
CompoundCondition = Constraint { Junction Constraint } ;
Constraint = [ "not" ] ( SimpleCondition | "(" CompoundCondition ")" ) ;
Junction = ( "and" | "or" ) ;
SimpleCondition = LeftOperand Comparator RightOperand ;
LeftOperand = <symbol> { <symbol> } ;
Comparator = ( "=" | "!=" | ">" | "<" | ">=" | "<=" | "matches" ) ;
RightOperand = ( <string> | <integer> | <floating> | <datetime> 
               | RightOperandValue | Parameter ) ;
Parameter = "parameter" ParameterName ;
RightOperandValue = <symbol> { <symbol> } ;
ParameterName = <symbol> { <symbol> } ;

See Grammar Notation in Syntax Sections for an explanation of the format and symbols used here



This defines a view class.  You must give it a name, and as opposed to object classes, you must also give it a parent class name.  You must specify at least one view member, but apart from that everything else is optional.


The name that you give a view class can consist of one or more symbols, and must be unique within the set of object classes, data classes and view classes in the package.


This is the mandatory parent class name.  The parent class must be in the same package as the view class.


The bases of a view class are used to consolidate the resulting selected view class instances.  There will be one result instance for each unique combination of the end point node values when the selection is made.  If you don't supply any bases, then, the number of result instances will multiply for every different scalar to collection movement in the traverses in the view class.


These are used in Bases, in ViewMembers and also in the LeftOperands of SimpleConditions.  The latter isn't shown in the syntax above, as LeftOperands can be items other than traverses.  See the section above for an explanation of how to write traverses.


A view class must have at least one view member.  These are the items that you want to see in the resulting selected view class instances, and Persistate generates a .Net property for each one in the ,Net class generated to hold the results.  The only mandatory clause in a view member definition is the traverse.  See above for details.  You can also supply a particular ViewMemberName, an Aggregate, or an order definition.

The order definition allows you order the result instances that are returned.  You can set up to ten orderings in view members.  You must set them in ordinal sequence without gaps.  So for example if you want to order by two view members, mark the first in first order and the second in second order.


The with SimpleCondition clause, although accepted, is non functional.  This is intended to produce a pivot type of function, and something like it will be included in a future version of Persistate.


By default, the name given to a view member is the same as the name of the member at the end point node of the traverse.  However, you can give it any name you want by including this clause.  If you include an aggregate clause, then you must supply a name with this clause.  View member names must be unique within the view class.


The Aggregate clause applies standard statistical functions to the view member.  The domain of the function is the set of end points of all the possible view member traverses from the root object, after any filtering by defined conditions, but before consolidation by the bases is performed.  If you use an aggregate, then you must supply a ViewMemberName clause.


This single clause can consist of any number of Constraints combined with and or or.  Each Constraint can be either  a SimpleCondition or a nested Compoundcondition in brackets, and can be preceded by not which reverses its value.  Note that you may not use both and and or in the same CompoundCondition.  You must always nest another one, within  parentheses, if you want to combine conjunction and disjunction.


This is a simple comparison between a LeftOperand and a RightOperand.  The standard operators can be used with most data classes, including multi-value classes.  The matches operator can only be used with the text data classes, and supports the wildcards % matching zero or more characters and _ matching exactly one character.


This can be one of two things.

It can be a view member name, in which case the value of the view member is compared.
It can be a traverse, in which case the value of the member at the end point of the traverse is compared.


This can be one of four things.

It can be a literal.  This can be a string, integer, floating point or datetime literal.  A string literal is any text within double quotes, with double quote itself represented by two consecutive double quotes.  Integer and floating point literals are as you would expect them.  A datetime literal is any text within single quotes which is parsed successfully by the .Net DateTime.TryParse method for the current culture.
It can be a parameter.  This is the word parameter followed by a name.  The name must be unique in the set of parameter names in the view class, and must be a valid identifier when converted to Pascal case.  Persistate will infer the appropriate type, and the generated select method for the view class will have a parameter with this name and type.
It can be a multi-value data class value name - essentially a multi-value literal.  In this case the LeftOperand member it is compared against must be of the appropriate type.
It can be a view member name, in which case the value of the view member is compared.