Entity(3NS)

NAME SYNOPSIS DESCRIPTION IMPLEMENTATION NOTES WARNINGS SEE ALSO AUTHORS

NAME

Entity - Abstract base class ythat handles persistance.

SYNOPSIS

Entity

Namespace Procedure Constructors

EntityCreate { entity }
EntityArrayCopy { entity }
EntityQuery { entity }
EntityNext { entity }
EntityInsert { entity }
EntityInsertUpdate { entity }
EntityUpdate { entity }
EntityUpdateWhere { entity }
EntityDelete { entity }
EntityDeleteWhere { entity }
EntityRefresh { entity }
EntityRetrieve { entity }
EntityMdtRetrieve { entity }
EntityGetAttribute { entity }
EntityValue { entity }
EntityRetrieveOidBy { entity }
EntityRetrieveObjBy { entity }
EntityGetListOf { entity }
EntityContainedList { entity }
EntityContainer { entity }
EntityCount { entity }
EntityTransition { entity }

Static Public Interface

Entity::Create { class objRef {selectList} }
Entity::ArrayCopy { class objRef {selectList} } : objList
Entity::Query { class objRef {where} {order} }
Entity::Next { class objRef } : 1(Success), 0(Failure)
Entity::Insert { class objRef } : oid
Entity::InsertUpdate { class objRef attr value {attr value} ... } : oid
Entity::Update { class objRef }
Entity::UpdateWhere { class objref attr value {attr value} ... }
Entity::Delete { class objRef }
Entity::DeleteWhere { class attr value {attr value} ... }
Entity::Refresh { class objRef } : 1(Success), 0(Failure)
Entity::Retrieve { class oid objRef {selectList} } : 1(Success), 0(Failure)
Entity::MdtRetrieve { class oid objRef } : 1(Success), 0(Failure)
Entity::GetAttribute { class {attribute} {property} {enumTagList} } : results - See documentation
Entity::ContainedList { class containerOid {selectList} } : objList
Entity::Container { class oid objref } : 1(Success), 0(Failure)
Entity::Value { class oid attr {value} } : value
Entity::RetrieveOidBy {class attr value ...} : oidList
Entity::RetrieveObjBy {class attr value ... } : objList
Entity::GetListOf {class attr} : valueList
Entity::Count { class {attr} {attr value} ... } : count
Entity::Transition { class event objref } : newState
Entity::EnumValue {enumValueList value} : enumValue {terse : Verbose}
Entity::Verbose {enumValue} : verboseValue
Entity::Terse {enumValue} : terseValue
Entity::Tag { enumValueList value } : tag
Entity::EnumMax {enumList} : lengthList {terselength verboselength}

Specific Private Interface

Entity::BuildWhere { class arrtRef } : whereStr
Entity::BuildOrder { class args } : orderClause
Entity::GetTableList { class objref } : tableList
Entity::SplitTables { class objref table } : objList

DESCRIPTION

Entity Specification

This section will walk through the process of specifying the Building Service entity as the example. Each Entity file contains a namespace definition, an initialization function, the standard procedure instantiations, and the specialized procedure defintions. Definition of an entity requires the following steps:

  1. Create the underlying database tables with the required attributes. This goes beyond the scope of this paper but the table constructor code for the examples are here for those interested:
  2. Define the Entity namespace with the directives and the attributes and their properties.
  3. Specify the set of standard procedures by applying the constructors.
  4. Specify the Initialization function
  5. Specify any specialized procedure definitions

Definition of the Namespace

A namespace definition contains a definition of directives, attributes and their properties, and entity initializations. While an entity can map to several database tables, each namespace should map to a single table. A namespace definition can then pull in other namespaces for a multiple table mapping. Definition of a namespace requires the following steps:

  1. Define a namespace

    The convention is to begin the Entity name with a capital letter. It does not have to be the same name as the underlying Table that the namespace represents. The convention in the example is to use the same name.

  2. Initialize any immediate base classes, contained classes, or referred to classes
  3. Set the Directives
  4. Import Base class and refers to class attributes
  5. Define the attributes and their properties
Entity Initializations

Initialize any immediate base classes or contained classes. Entity Initialization for BuildingService are as follows:

namespace eval BuildingService {
   variable this
   variable attr
   cariable oid
   variable dt
   variable buildingLocation

   # Insure the base class is initialized
   ServiceInit

   #Insure the refers to class is initialized
        #The refers to class is initialized in Service according to the model

   #Insure the contained class is Initialized
         #There are no contained classes
   .
   .
   .   
}  
Directives

Each namespace contains certain required directives in a this array. These directives define the relationships of the entity to other entities and to the underlying database table or tables. Each directive will be described.

The directives provide a mapping from the entity to one or more database tables. An Entity can map to a single database table or to several database tables with the case of inheritance or other relationships. The following relationships can be encapsulated with an entity

this(from)
This directive contains the from clause for doing a SQL select join, (read-only access to the tables). Each table in an inheritance or reference relationship must be specified here. It is important to specify aliases for each table. The aliases for any base table must match the alias given in that base entity definition. All aliases must be unique with a given namespace defintion (eg. the base alias is different from the derived alias). Specify the base table followed by their derivatives in the derived order by a comma separated list. The order is important. If a table stands alone, it just has a table name and alias. The most derived entity is the one being specified here. This clause must contain each table in the entire inheritance hierarchy, not just the immediate base table.
this(table)
This directive contains the table name and an alias. If this entity stands alone (no base class), this is identical to this(from). An alias must be provided.
this(class)
This contains the name of the namespace.
this(containedClass)
This directive specifies a Tcl list (space separated) of contained classes. Specify the most derived entity name for each contained entity. If no entities are contained, set to {}.
this(where)
This contains the join constraint portion of a SQL where clause. There must be one constraint for each table joined. For three tables, (aliases a, b, c) the join constraint would look somethig like "a.oid=b.oid and b.oid=c.oid" If this entity stands alone, set to {}.
this(hierarchy)
This is a Tcl list of class names of the inheritance hierarchy starting with the base Entity and ending with the most derived Entity (the one being defined here). The order is important since this will affect the order that tables are written. Note also, that this directive specifies write access to the table. This may differ from the this(from) directive when static tables (read-only) are part of an object. If a table is not to be written to it must not be specified here. If the Entity is a stand-alone, set to this(class)
this(dbObject)
This specifies the DbObject class to use. An entity can be initialized with the database interface. The Sybase DbObject is the default.
this(inst)
This specifies the connection instance to use. The connection to the database is gotten external to the entity and must be given on entity initialization. The default is 1.

An example of the directives for BuildingService is as follows:

namespace eval BuildingService {
   .
   .
   .
   #The directives
   #This is a derived class so a join is needed with the base class and any refers to classes
   #The from clause specifies the tables and aliases to be read in order from base to derived
   #Table specifies the derived table name and alias
   #Class specifies the namespace
   #Where specifies the join constraint
   #Hierarchy specifies the order of the tables to be written from base to derived

   set this(from) "ManagedObj m, Service s, ServiceDescription sd, BuildingService bs"
   set this(table) "BuildingService bs"
   set this(class) BuildingService
   set this(containedClass) {}
   set this(container) {ManagedObj}
   set this(where) "m.oid = s.managedObjOid and s.serviceDescriptionOid = sd.oid and bs.serviceOid = s.managedObjOid"
   set this(hierarchy) [list ManagedObj Service $this(class)]
   .
   .
   .
}
Import Base Class Attributes

Base class attributes must be imported before defining the derived class attributes. They are imported using the standard interface procedure, GetAttribute. The base class for BuildingService is Service as follows:

namespace eval BuildingService {
   .
   .
   .
   #Import the Base class attributes
   array set attr [Service::GetAttribute]
   .
   .
   .
}
Attributes

There are required attributes for different situations which are sumarized as follows

All attributes must map one-to-one to the columns of the table. The column names do not have to match the attribute names.

Attribute Properties

An example of the attributes and properties for BuildingService is defined as follows:

namespace eval buildingService {
   .
   .
   .
   #Specify the derive class attributes
   #oid
   lappend this(attrs) oid
   set oid(type) Integer
   set oid(key) Foreign
   set oid(column) {bs.serviceOid)
   set oid(table) $this(class)
   set oid(defWidth) 9
   set oid(label) {}
   set oid(default) {}
   set attr(oid) [array get oid]
   #dt
   lappend this(attrs) dt
   set dt(type) Text
   set dt(column) {bs.dt}
   set dt(table) $this(class)
   set dt(label) {(a,A - z,Z); 24 characters max}
   set dt(defWidth) 24
   set dt(default) {}
   set attr(dt) [array get dt]
   #buildingLocation
   lappend this(attrs) buildingLocation
   set buildingLocation(type) Text
   set buildingLocation(table) $this(class)
   set buildingLocation(label) {(a,A - z,Z); 50 characters max}
   set buildingLocation(defWidth) 50
   set buildingLocation(column) {bs.buildingLocation}
   set buildingLocation(default) {}
   set attr(buildingLocation) [array get buildingLocation]
     #Import base class attr list
   set this(attrs) [union $this(attrs) $Service::this(attrs)]
}

This is the Entity namespace specification. Notice the easy mapping from the information in the object model. This is a candidate for automatic code generation.

Standard Procedure Constructors

The standard set of constructors are specified in the form

<standard procedure constructor> <newEntity::this(class)>

These are intialized outside the namepace definition.

      //Always Specify
EntityCreate $MyEntity::this(class)
EntityQuery $MyEntity::this(class)
EntityNext $MyEntity::this(class)
EntityRefresh $MyEntity::this(class)
EntityGetAttribute $MyEntity::this(class)
EntityGetListOf $MyEntity::this(class)
EntityRetrieve $MyEntity::this(class)
EntityMdtRetrieve $MyEntity::this(class)
EntityRetrieveOidBy $MyEntity::this(class)
EntityRetrieveObjBy $MyEntity::this(class)
EntityArrayCopy $MyEntity::this(class)
EntityCount $MyEntity::this(class)

      //Optional
EntityInsert $MyEntity::this(class)
EntityInsertUpdate $MyEntity::this(class)
EntityUpdate $MyEntity::this(class)
EntityUpdateWhere $MyEntity::this(class)
EntityDelete $MyEntity::this(class)
EntityDeleteWhere $MyEntity::this(class)
EntityContainedList $MyEntity::this(class)
EntityContainer $MyEntity::this(class)
EntityValue $MyEntity::this(class)

The behavior of an entity can be controlled by selective specification. Overriding the standard behavior is done by not specifying the constructor and redefining the standard procedure within this file. The following rules apply for different entities.

  1. Persistent Abstract Base class - Remove the EntityInsert.
  2. Read-only Entity - Remove the EntityInsert, EntityUpdate, EntityDelete, and perhaps EntityValue.
  3. A non-contained entity - Remove EntityContainedList.

Initialization Procedure

The namespace is loaded by the following initialization function. Invocation of this function causes the Tcl interpreter to load the namespace. It also allows the entity to be initialized with a different DbObject and connection instance.

proc BuildingServiceInit { {db DbObject} {connection 1} } {
   set BuildingService::this(dbObject) $db
   set BuildingService::this(inst) $connection
}

Virtual Procedure definition

Occasionally it is neccesary to override the standard interface procedure with one that enforces specific business rules. I provide an example of theServiceInsert override to implement the automatic linkage with the ServiceDescription instance. This example also serves to show how the standard interface is used within a program

proc BuildingService::Insert {objref} {
   upvar $objref obj
   variable this

   #Test if ServiceDescriptionOid or serviceName are provided and valid
   if {[ string match $obj(serviceDescriptionOid) {} ]} {
      #See if serviceName was provided
      if {[ string match $obj(serviceName) {} ]} {
         error "BuildingService::Insert failed.  Object reference doesn't contain a ServiceDescriptionOid or serviceName."
   } else {
      #validate serviceName and obtain ServiceDescriptionOid
      set serviceOid [ServiceDecription::RetrieveOidBy serviceName $obj(serviceName)]
      if {[ string match $serviceOid {} ]} {
         error "BuildingService::Insert failed.  The provided serviceName, $obj(serviceName), is not valid"
      } else {
         set obj(serviceDescriptionOid) $serviceOid
      }
   } else {
      #validate the serviceDescriptionOid
      if { ![ServiceDescription::Count * oid $obj(serviceDescriptionOid)] } {
         error "BuildingService::Insert failed.  The provided serviceDescriptionOid is not valid."
      }
   }
   #Insert into Database
   return [Entity::Insert $this(class) obj]
}

EntityCreate {entity}

A template constructor that makes a Create procedure in the given entity namespace in the form,

proc <entity>::Create { objref {selectList {}} }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Create Procedure belongs.
Outputs: None
Returns: None

EntityArrayCopy {entity}

A template constructor that makes a ArrayCopy procedure in the given entity namespace in the form,

proc <entity>::ArrayCopy { objref {selectList {}} }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the ArrayCopy Procedure belongs.
Outputs: None
Returns: None

EntityQuery {entity}

A template constructor that makes a Query procedure in the given entity namespace in the form,

proc <entity>::Query { objref {where{}} {order {}} }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Query Procedure belongs.
Outputs: None
Returns: None

EntityNext {entity}

A template constructor that makes a Next procedure in the given entity namespace in the form,

proc <entity>::Next { objref }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Next Procedure belongs.
Outputs: None
Returns: None

EntityInsert {entity}

A template constructor that makes a Insert procedure in the given entity namespace in the form,

proc <entity>::Insert { objref }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Insert Procedure belongs.
Outputs: None
Returns: None

EntityInsertUpdate {entity}

A template constructor that makes a InsertUpdate procedure in the given entity namespace in the form,

proc <entity>::InsertUpdate { objref }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Insert Procedure belongs.
Outputs: None
Returns: None

EntityUpdate {entity}

A template constructor that makes a Update procedure in the given entity namespace in the form,

proc <entity>::Update { objref }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Update Procedure belongs.
Outputs: None
Returns: None

EntityUpdateWhere {entity}

A template constructor that makes an UpdateWhere procedure in the given entity namespace in the form,

proc <entity>::UpdateWhere { objref attr value {attr value} ...} : oidList

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the UpdateWhere Procedure belongs.
Outputs: None
Returns: None

EntityDelete {entity}

A template constructor that makes a Delete procedure in the given entity namespace in the form,

proc <entity>::Delete { objref }

This procedure is to be created on-the-fly right after the namespace is first created.

A different Delete procedure is created depending on whether the given entity contains the attribute, mdt.

Inputs:
entity - The namespace to which the Delete Procedure belongs.
Outputs: None
Returns: None

EntityDeleteWhere {entity}

A template constructor that makes a DeleteWhere procedure in the given entity namespace in the form,

proc <entity>::DeleteWhere { objref attr value {attr value} ...}

This procedure is to be created on-the-fly right after the namespace is first created.

A different DeleteWhere procedure is created depending on whether the given entity contains the attribute, mdt.

Inputs:
entity - The namespace to which the DeleteWhere Procedure belongs.
Outputs: None
Returns: None

EntityRefresh {entity}

A template constructor that makes a Refresh procedure in the given entity namespace in the form,

proc <entity>::Refresh { objref }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Refresh Procedure belongs.
Outputs: None
Returns: None

EntityGetAttribute {entity}

A template constructor that makes a GetAttribute procedure in the given entity namespace in the form,

proc <entity>::GetAttribute { {attribute {}} {property {}} {enumTagList {}} }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the GetAttribute Procedure belongs.
Outputs: None
Returns: None

EntityValue {entity}

A template constructor that makes a Value procedure in the given entity namespace in the form,

proc <entity>::Value { oid attr {value {}} }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Value Procedure belongs.
Outputs: None
Returns: None

EntityRetrieveOidBy {entity}

A template constructor that makes a RetrieveOidBy procedure in the given entity namespace in the form,

proc <entity>::RetrieveOidBy { attr value args }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the RetrieveOidBy Procedure belongs.
Outputs: None
Returns: None

EntityRetrieveObjBy {entity}

A template constructor that makes a RetrieveObjBy procedure in the given entity namespace in the form,

proc <entity>::RetrieveObjBy { attr value args }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the RetrieveObjBy Procedure belongs.
Outputs: None
Returns: None

EntityGetListOf {entity}

A template constructor that makes a GetListOf procedure in the given entity namespace in the form,

proc <entity>::GetListOf { attr }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the GetListOf Procedure belongs.
Outputs: None
Returns: None

EntityCount{entity}

A template constructor that makes a Count procedure in the given entity namespace in the form,

proc <entity>::Count { {attr} {attr value} ... } : count

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Count Procedure belongs.
Outputs: None
Returns: None

EntityContainedList {entity}

A template constructor that makes a ContainedList procedure in the given entity namespace in the form,

proc <entity>::ContainedList { containerOid {selectList {}} }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the ContainedList Procedure belongs.
Outputs: None
Returns: None

EntityContainer{entity}

A template constructor that makes a Container procedure in the given entity namespace in the form,

proc <entity>::Container { oid objref } :1(Success), 0(failure)

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Container Procedure belongs.
Outputs: None
Returns: None

EntityRetrieve {entity}

A template constructor that makes a Retrieve procedure in the given entity namespace in the form,

proc <entity>::Retrieve { oid objref }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the Retrieve Procedure belongs.
Outputs: None
Returns: None

EntityMdtRetrieve {entity}

A template constructor that makes a MdtRetrieve procedure in the given entity namespace in the form,

proc <entity>::MdtRetrieve { oid objref }

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
entity - The namespace to which the MdtRetrieve Procedure belongs.
Outputs: None
Returns: None

EntityTransition {entity}

A template constructor that makes a Transition procedure in the given entity namespace in the form,

proc <entity>::Transition { event objref } : newState

This procedure is to be created on-the-fly right after the namespace is first created.

Inputs:
event - The event that causes the transition.
objref - the object instance on which to transition.
Outputs: None
Returns:
newState - The new state of the object instance after the transition occurs.

<entity>::Create { objref {selectList {}} }

This procedure initializes the given objref name into an array with the attributes given in selectList. the attributes, oid, mdt, and dt are always included if they exist in the entity. If no attributes are given, the array is initialized with all attributes in the entity object of the given class. The array attributes are initialized to the default values. No interaction with the database occurs.

Example Usage
Building::Create b "createDate"

Creates an array with default values
b(oid) {}
b(mdt) {}
b(dt) {}
b(createDate) function getdate()

This Procedure is a wrapper which passes the entity class into the static procedure, Entity::Create, which fully implements the behavior.

Created by a template constructor, EntityCreate

Inputs:
selectList - [default {}] A tcl list of the attributes to be populated in the objref entity array
Outputs:
objref - A reference to an entity array. An initialized array with default values
Returns: None

<entity>::ArrayCopy { objref {selectList {}} }

This procedure returns a copy array list of the given objref array. If a selectList is provided, the returned array list contains only copies of the specified items plus internals such as oid, dt, and mdt. If no selectList is provided, it copies the entire entity-defined array. This can act as a filter to remove any composite attributes. It

  1. Creates the selectList
  2. Copies to a temp array the value for each given attr in objref that exists in the select list. Any existing attribute in objref not contained in the select list does not get copied, filtering out attributes not belonging to the entity.
  3. Returns the array listing for temp array.
Example Usage
array set newManagedObj [ManagedObj::ArrayCopy t "action adminState"]

Copies the array t, into newManagedObj but only the following values
newManagedObj(oid) 25002432
newManagedObj(mdt) Building
newManagedObj(dt) {}
newManagedObj(action) I: Inserted
newManagedObj(adminState) U: Unlocked

This Procedure is a wrapper which passes the entity class into the static procedure, Entity::ArrayCopy, which fully implements the behavior.

Created by a template constructor, EntityArrayCopy

Inputs:
objref - A reference to an entity array representing the object instance.
selectList - [default {}] A tcl list of the attributes to be copied in the return array listing
Outputs: None
Returns: None
array listing - A subcomponent of the given objref. Use array set to form a copy array.

<entity>::Query { objref {where {}} {order {}} }

This procedure sets up a query that may involve a join across multiple tables, depending on how the entity is defined. The given objref array specifies the attributes that are to be retrieved. The where clause and order by clause specify the filtering and ordering of the retrieved results. Since the where and order clauses are raw SQL strings, the application programmer is encouraged to define new member procedures so these SQL specifications remain private to this object. It is implemented by calling DbObject::Query

Example Usage
ManagedObj::Query m "coid = $parentOid" "oid asc"

This send off a query for the attributes contained in array m where the coid=parentOid. Results are retrieved by ManagedObj::Next is ascending order by oid.

This Procedure is a wrapper which passes the entity class into the Database interface class procedure, DbObject::Query, which fully implements the behavior.

Created by a template constructor, EntityQuery

Inputs:
objref
A reference to an entity array representing the object instance. The attributes specified become the select list in the SQL, meaning only those values are returned in the query
where
[default {}] - the where string for the SQL statement. This is a raw where clause that does not include join constraints. All column names and values are database specific. Do not include the word, where.
order
[default {}] - the order by clause for the SQL statement. All column names are database specific. Do not include the word order by.
Outputs: None
Returns: None

<entity>::Next { objref }

This procedure retrieves the query results. It is important that the given objref array is the same as the array used in Entity::Query. Each attribute is given the value returned by the query and an oid is also assigned if the return code is 1. It is implemented by calling DbObject::Next

Example Usage
while {[ManagedObj::Next m ]} {
   parray m
}

This procedure loads the array m with the contents of a query and returns a 1. When no more information is available, the procedure returns 0

This Procedure is a wrapper which passes the entity class into the Database interface class procedure, DbObject::Next, which fully implements the behavior.

Created by a template constructor, EntityNext

Inputs: None
Outputs:
objref - A reference to an entity array representing the object instance given to <entity>::Query. Each attribute is given the value returned by the query and an oid is also assigned if the return code is 1.
Returns:
1 - A row is available; 0 - No rows returned.

<entity>::Insert { objref }

This procedure inserts the object into the database. If the object is implemented as an inheritance hierarchy, it will divide the data acording to table and inserts it into the all of the proper tables in the proper order, thus hiding the inheritance implementation. It also automatically does the derived and most derived type bookkeeping. The oid is returned. It

  1. If the data in the given array crosses multiple tables, determined by calling Entity::GetTableList, a transaction is started by calling DbObject::Begin
  2. For each table in the hierarchy, this(hierarchy), (listed in order from base class to most derived)
    1. Split the given object to get the subset of attributes that belong to the given table by calling Entity::SplitTables
    2. If an mdt (most derived table) exists, Set the mdt to the current class if the table is a base class table
    3. If the dt (derived table) exists, Set the dt to the next table in the list. the most derived table gets a null.
    4. Do the insert by calling DbObject::Insert
  3. Commit the transaction (if in a transaction) and return the oid
Example Usage
set newOid [ManagedObj::Insert m]

This procedure inserts the entity into the database using the information inside array m and returns the oid. It also sets m(oid).

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Insert, which fully implements the behavior.

Created by a template constructor, EntityInsert

Inputs:
objref - A reference to an entity array representing the object instance. Only the values of the attributes given in the array are populated in the database.
Outputs:
objref(oid) - the unique identifier for the object
objref(mdt) -(if it exists) - the most derived type of an inheritance hierarchy
objref(dt) - (if it exists) - the derived type of an inheritance hierarchy
Returns:
oid - the unique identifier for the object.

<entity>::InsertUpdate { objref attr value args }

This procedure will search for an object specified by the attr and value pairs. One or more attribute and value pairs may be specified in the args list. A "!" preceding the value in the parameter list translates to attr !=value in the constructed where clause. If the object is not found, this procedure inserts the object and returns the oid. If the object is found, this procedure updates the object and returns the oid.

  1. Builds a where clause to search for the given values, formatting the values by calling DbObject::BuildType.
  2. Queries the database with a temporary object and the constructed where clause by calling DbObject::Query.
  3. If an object is found, retrieves the oid and calls <Derived class>::Update to update the object with the values specified in the objref array.
  4. If more than one object is found, generates an error.
  5. If no objects are found, calls <Derived class>::Insert to insert the object with the values specified in the objref array.
  6. Returns the oid of the updated or inserted object.
Example Usage
Service::InsertUpdate s owner $owner serviceName !ARAMARK

This procedure searches the database using the where clause, where owner=$owner and serviceName !=ARAMARK. If the object is not found, this procedure inserts the object into the database using the data in s. If the object is found, this procedure updates the object in the database using the data in s.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::InsertUpdate, which fully implements the behavior.

Created by a template constructor, EntityInsertUpdate

Inputs:
objref - A reference to an entity array representing the object instance.
attr - The first attribute for which to search the entity table.
value - The value of the given attribute to find.
args - An optional list of attribute and value pairs for which to search the entity table.
Outputs: None
Returns: None
oid - The oid of the object inserted or updated.

<entity>::Update { objref }

This procedure updates the object represented by the given objref array. This array must contain a valid oid. Only the values of the attributes represented in the array are updated in the database so parts of the object can be updated. If the object is implemented as an inheritance hierarchy, it will divide the data acording to table and update it into the all of the proper tables in the proper order, thus hiding the inheritance implementation. It

  1. If the data in the given array crosses multiple tables, determined by calling Entity::GetTableList, a transaction is started by calling DbObject::Begin
  2. For each table in the hierarchy, this(hierarchy), (listed in order from base class to most derived)
    1. Split the given object to get the subset of attributes that belong to the given table by calling Entity::SplitTables
    2. Do the update by calling DbObject::Update
  3. Commit the transaction (if in a transaction).
Example Usage
set m(action) [ManagedObj::GetAttribute action enum inserted]
ManagedObj::Update m

This procedure update the entity in the database using the information inside array m

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Update, which fully implements the behavior.

Created by a template constructor, EntityUpdate

Inputs:
objref - A reference to an entity array representing the object instance. Only the values of the attributes given in the array are updated in the database.
Outputs: None
Returns: None

<entity>::UpdateWhere{ objref attr value args} : oidList

This procedure is used to make updates to multiple instances in a single transaction. This procedure updates any instance whose value(s) match the given attribute(s). It returns an oidList of the instances that were updated. It

  1. Creates an argsList of attribute-value pairs
  2. Retrieves a list of objects that match the given attribute-value argslist by calling <entity>::RetrieveOidBy
  3. Begina a transaction by calling DbObject::Begin if multiple objects are updated.
  4. For each object, set the oid into the given objref array and update the object by calling <entity>::Update.
  5. Commit the transaction (if in a transaction) by calling DbObject::Commit
Inputs:
objref - A reference to an entity array representing the object instance. Only the values of the attributes given in the array are updated in the database.
attr - The first attribute for which to search the entity table
value - The value of the given attribute to find
args - An optional list of attribute-value pairs to further specify the search.
Outputs: None
Returns:
oidList - a list of instances that were updated.

<entity>::Delete { objref }

This procedure deletes the entity represented by the given objref array. It requires attributes, oid, mdt (for inheritance), and coid (for containment), since this tells the procedure which entity(s) to delete. If the object crosses multiple tables, this procedure will delete all data relating to the object. If <entity>::Delete is called on a base class, the entire entity is deleted since delete is implemented by calling DbObject::Delete on the most derived type, mdt. If the entity contains other entities, a delete operation is executed on each of these contained entities. It

  1. Validates that mdt is set if it exists in this entity.
  2. If coid exists, begin a transaction, find all contained entities in the base class and delete each one and then end the transaction
  3. If the data in the given array crosses multiple tables, determined by calling Entity::GetTableList, a transaction is started by calling DbObject::Begin
  4. For each table in the hierarchy, this(hierarchy), (listed in order from base class to most derived), Delete each table by calling DbObject::Delete
  5. Commit the transaction (if in a transaction).
Example Usage
ManagedObj::Delete m

This procedure deletes the entity in the database using the information inside array m

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Delete, which fully implements the behavior. If mdt exists and is set, the mdt class is passed to the procedure so the most derived entity and its inheritance chain is properly deleted.

Created by a template constructor, EntityDelete

Inputs:
objref - A reference to an entity array representing the object instance.
Outputs: None
Returns: None

<entity>::DeleteWhere{ objref attr value args}

This procedure is used to delete multiple instances in a single transaction. This procedure deletes any instance whose value(s) match the given attribute(s). It

  1. Creates an argslist of attribute-value pairs
  2. Retrieves a list of objects that match the given attribute-value argslist by calling <entity>::RetrieveObjBy
  3. Begin a transaction by calling DbObject::Begin if multiple objects are to be deleted
  4. For each object, delete it by calling <entity>::Delete
  5. Commit the transaction (if in a transaction) by calling DbObject::Commit
Inputs:
objref - A reference to an entity array representing the object instance.
attr - The first attribute for which to search the entity table
value - The value of the given attribute to find
args - An optional list of attribute-value pairs to further specify the search.
Outputs: None
Returns: None

<entity>::Refresh { objref }

This procedure refreshes the data in the object represented by the given objref array. The only required attribute value is the oid since this tells the procedure which object to refresh. The attributes in the array indicate what data is to be refreshed. If the object crosses multiple tables, this procedure will refresh all data in the objref array.

  1. Execute a query where the oid is that value in the array by calling DbObject::Query
  2. Retrieve the information and load up the array, objref, by calling DbObject::Next and return its return code.
Example Usage
ManagedObj::Refresh m

This procedure refreshes the data in array m from the database. It returns a 1 if successful.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Refresh, which fully implements the behavior.

Created by a template constructor, EntityRefresh See Entity::Refresh

Inputs:
objref - A reference to an entity array containing the attributes to be refreshed.. The oid is required
Outputs:
objref - A reference to an entity array representing the object instance. The values now reflect the database if successful.
Returns:
1 - Successful; 0 Unsuccessful

<entity>::Retrieve { oid objref {selectList{}} }

This procedure retrieves an object given by oid and populates the given objref array. It is a shortcut for the programmer if the oid is known. If selectList is given, only those attributes are populated in the array. It

Example Usage
ManagedObj::Retrieve $oid m
This procedure loads the data in the given array name m from the database object indicated by $oid. It returns a 1 if successful.
ManagedObj::Retrieve $oid m "action adminState coid"
This procedure loads the array name t with the data, (oid, mdt, dt are loaded by default), action, coid, and adminState from the database object indicated by $oid. It returns 1 if successful

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Retrieve, which fully implements the behavior.

Created by a template constructor, EntityRetrieve

Inputs:
oid - The object id to retrieve
Outputs:
objref - A name of an entity array representing the object instance. This procedure populates the array.
Returns:
1 - Successful; 0 Unsuccessful

<entity>::MdtRetrieve { oid objref }

This procedure retrieves a most derived object given by oid and populates the given objref array. This procedure is called from a base class and retrieves its most derived class. It is a shortcut for the programmer if the oid is known. It

Example Usage
ManagedObj::MdtRetrieve $oid m
This procedure loads the data in the given array name m from the database object indicated by $oid.
If the $oid belongs to a derived class of ManagedObj (Building for example), this procedure loads the data in the given array name m from the derived database object. It returns 1 if successful.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::MdtRetrieve, which fully implements the behavior.

Created by a template constructor, EntityMdtRetrieve

Inputs:
oid - The object id to retrieve
Outputs:
objref - A name of an entity array representing the object instance. This procedure populates the array.
Returns:
1 - Successful; 0 Unsuccessful

<entity>::GetAttribute { {attribute {}} {property {}} {enumTagList} }

This procedure retrieves the static attribute property information for the given class.

  1. If no parameters are given, the instance list of all of the attributes and properties is returned. Use array set to convert the list to an array of attributes and their properties.
  2. If the attribute is given, the instance list of the properties for that attribute is returned. Use array set to convert the list to an array of properties for that attribute.
  3. If the attribute and the property are given, the single property value is returned.
  4. If the attribute is given with a property of enum and the enumTagList is given, the enumerated value or values is returned. See below
Example Usage
array set attr [ManagedObj::GetAttribute]

The attr array is an array of all attributes and their properties for the entire entity. This is used to populate a derived entity with the base class entity attributes.

array set mdt [ManagedObj::GetAttribute mdt]

mdt is an array of the properties of the mdt attribute in the entity. This is used whenever the programer wants to pick and choose certain attributes for an entity such as a view management entity.

mdt(type) Text
mdt(column) m.mdt
mdt(table) ManagedObj
mdt(label) {(a,A - z,Z); 10 characters max}
mdt(defWidth) 10
mdt(default) {}
set column [ManagedObj::GetAttribute mdt column]

This retrieves the column name (for example m.mdt) for the mdt attribute.

array set domain [ManagedObj::GetAttribute action enum]

This creates an array, domain, as follows

action(inserted) I: Inserted
action(updated) U: Updated
action(deleted) D: Deleted
set domain [ManagedObj::GetAttribute action enum updated]

This returns the value of the production enumeration, U: Updated

set values [ManagedObj::GetAttribute action enum "inserted deleted"]

This returns the values of the specified tags, {I: Inserted} {D: Deleted}

set tags [ManagedObj::GetAttribute action enum tags]

This returns a tcl list of the domain tags, inserted, updated, deleted.

set values [ManagedObj::GetAttribute action enum values

This returns the list of values to the enumerations, {I: Inserted} {U: Updated} {D: Deleted}

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::GetAttribute, which fully implements the behavior.

Created by a template constructor, EntityGetAttribute

Inputs:
attribute - (optional) - the wanted attributes and properties.
property - (optional) - [type, column, key, enum, table, defwidth, label, default] - the single wanted property of a given attribute.
enumTagList - (optional) - [tags, values, <tag>, <tagList>] -
Outputs: None
Returns:
Inputs Returns
no parameters The list of all of the attributes and their properties. Use "array set to form an array of attributes.
<attribute> The list of all of the properties for that attribute. Use "array set to form an array of properties for that attribute
<attribute> <property> A single value for the property of that attribute.
<attribute> enum <tag> A single corresponding enumerated value of the form, {T: Verbose}
<attribute> enum <tagList> A list of corresponding enumerated values of the form, {T: Verbose}
<attribute> enum tags A list of allowable enumeration tags that are used in the code.
<attribute> enum values A list of allowable enumeration values of the form, {T: Verbose}

<entity>::ContainedList { containerOid {selectList} }

This procedure will find the objects contained within the object of given containerOid. It returns a list of entities. If the selectList is given, it only returns the values specified. It

  1. Creates an entity with the contents of the given selectList by calling Entity::Create.
  2. Queries the database for any coid that match the given containerOid by calling DbObject::Query
  3. Appends each found entity by calling DbObject::Next and returns the list.
Example Usage
foreach objList [BuildingService::ContainedList $containerOid] {
   array set bs $objList
   parray bs
}

This procedure returns a list of BuildingService arrays that are contained within the entity of oid $containerOid.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::ContainedList, which fully implements the behavior.

Created by a template constructor, EntityContainedList

Inputs:
containerOid - the oid of the container
selectList - (optional) - A list of attributes to retrieve. The entire entity is retrieved if none are specified.
Outputs: None
Returns:
objList -A list of contained entities; Use foreach to process them

<entity>::Container{ oid objref } : 1(Success, 0(Failure)

This procedure, given the containee oid, polymorphically retrieves its container object and populates the container objref array. It is a shortcut for the programmer if the oid is known. It

  1. Retrieve the indicated object's coid using the given oid by calling <entity>::Value.
  2. Retrieves the container using the coid by calling MdtRetrieve
    Example Usage
    BuildingService::Container $oid b

    This procedure loads the Building data in the given array name, b from the database object indicated by oid by using the retieved object's coid. It returns a 1 if successful.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Container, which fully implements the behavior.

Created by a template constructor, EntityContainer

Inputs:
oid - the object id whose container we want to retrieve.
Outputs:
objref - A name of the container array. This procedure populates the array.
Returns:
1 - Successful; 0 - Unsuccessful

<entity>::GetListOf { attr }

This procedure can be used to produce a list for optionMenus etc. It returns a list of all values in the database corresponding to the given attribute. This procedure is only applicable to tables such as static tables where the given attr is unique. It

  1. Creates an entity that includes the given attr by calling Entity::Create
  2. Queries the database specifying an ascending order of the given attr by calling DbObject::Query
  3. Appends each found attr value by calling DbObject::Next and returns the list.
Example Usage
set valueList [ServiceDescription::GetListOf serviceName]

This procedure returns a list of service names to populate, for example, and option menu.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::GetListOf, which fully implements the behavior.

Created by a template constructor, EntityGetListOf

Inputs:
attr - The attribute that we want listed.
Outputs: None
Returns:
valueList - The list of values of the given attribute

<entity>::Count{ {attr} args} : count

This procedure can be used to count instances. If no attr is given or '*' is specified, it returns a count of all instances. If attr is provided, it returns a count of all distinct values for that attribute. The parameter, args (otherwise shown as {attr value} ...), if given, will define a where clause using attr-value pairs that further constrains the count. A "!" preceding the value in the arg list translates to attr !=value in the constructed where clause. This procedure is only applicable to tables such as static tables where the given attr's values are unique. It

  1. Creates a where clause from the given attr-value list to search for the given values, by calling Entity::BuildWhere.
  2. Queries the database specifying an ascending order of the given attr by calling DbObject::GetListOf
  3. Returns the count.
Example Usage
set count [BuildingService::Count]

or

set count [BuildingService::Count *]

This procedure (either form) counts the number of BuildingService instances.

set count [BuildingService::Count serviceName]

This procedure counts the number of distinct serviceNames in the BuildingService instances.

set count [BuildingService::Count serviceName serviceType food]

This procedure counts the number of distinct serviceNames of the serviceType food.

set count [BuildingService::Count * serviceType food]

This procedure counts the total BuildingService instances of the serviceType food.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Count, which fully implements the behavior.

Created by a template constructor, EntityCount

Inputs:
attr - (optional [default *]) - The attribute for which a distinct count is to be made.
args - ({attr value} ...) - An optional list of attribute-value pairs for which to search the entity table.
Outputs: None
Returns:
count - A count of all distinct values for the attribute given, if given, that match the attr-value constraints.

<entity>::RetrieveOidBy {class attr value args }

This procedure can be used to populate oids in entities. It will search for the given attributes and their corresponding unique values specified in attr, value and the args list. One or more attribute and value pairs may be specified in the args list. A "!" preceding the value in the parameter list translates to attr !=value in the constructed where clause. A list of Oids is returned. The procedure RetrieveOidBy

  1. Creates an entity that includes the given attributes in attr and the args list by calling Entity::Create
  2. Creates a where clause to search for the given values, formatting the value by calling DbObject::BuildType
  3. Queries the database using the constructed where clause by calling DbObject::Query
  4. Appends each found oid value by calling DbObject::Next and returns the oid list.
Example Usage
set oid [lindex [Building::RetrieveOidBy buildingName $buildingName buildingNumber !101] 0]

This procedure returns a list of oids for the Building entity of the given buildingName and buildingNumber attributes. The where clause constructed would be as follows: where buildingName=$buildingName and buildingNumber !=101

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::RetrieveOidBy, which fully implements the behavior.

Created by a template constructor, EntityRetrieveOidBy

Inputs:
attr - The first attribute for which to search the entity table.
value - The value of the given attribute to find.
args - An optional list of attribute and value pairs for which to search the entity table.
Outputs: None
Returns:
oidList - A list of Oids to match the above search.

<entity>::RetrieveObjBy { attr value args }

This procedure will find the objects in the entity that match the given attributes and their corresponding unique values specified in attr, value and the args list. One or more attribute and value pairs may be specified in the args list. A "!" preceding the value in the parameter list translates to attr !=value in the constructed where clause. It returns a list of entity objects. The procedure RetrieveObjBy

  1. Creates an entity that includes the given attributes in attr and the args list by calling Entity::Create
  2. Creates a where clause to search for the given values in attr, value and the args list, formatting the values by calling DbObject::BuildType
  3. Queries the database using the constructed where clause by calling DbObject::Query
  4. Appends each found obj value by calling DbObject::Next and returns the obj list.
Example Usage
foreach objList [Building::RetrieveObjBy buildingName $buildingName buildingNumber !101] {
            array set building $objList
            parray building
         }

This procedure returns a list of Building objects that are found matching the specified values of the attributes buildingName and buildingNumber defined in attr, value and the args list. The where clause constructed would be as follows: where buildingName=$buildingName and buildingNumber !=101

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::RetrieveObjBy, which fully implements the behavior.

Created by a template constructor, EntityRetrieveObjBy

Inputs:
attr - The first attribute for which to search the entity table.
value - The value of the given attribute to find.
args - An optional list of attribute and value pairs for which to search the entity table.
Outputs: None
Returns:
objList - A list of objects that match the above search.

<entity>::Value { oid attr value }

This procedure is a generic accessor function for setting or getting a single value. If value is not given, a single value for the entity is returned from the database. If value is given, the single value is saved to the database. It

  1. Creates an entity that includes the given attr by calling Entity::Create
  2. If no value is given, it retrieves the value by calling Entity::Refresh and returns the value.
  3. If a value is given, it updates the entity by calling Entity::Update and then returns the value
Example Usage
set buildingName [Building::Value $oid buildingName]

This procedure returns the buildingName for the Building entity of the given $oid.
Building::Value $oid buildingName $buildingName

This allows the buildingName attribute to be set to the value $buildingName in the Building entity, $oid.

This Procedure is a wrapper which passes the entity class into the static entity procedure, Entity::Value, which fully implements the behavior.

Created by a template constructor, EntityValue

Inputs:
oid - The object identifier to set or get.
attr - The attribute to get (if no value is given) or set to the value given
value - The value of the attribute to set.
Outputs: None
Returns:
value - The value of the attribute

Entity::EnumValue

This procedure searches the given list for the given terse or verbose value and returns the enum value of form {Terse: Verbose} if found. It returns the given value if not found.

Inputs:
enumValueList - a list of enumValues, {Terse:Verbose}... or a list of enum Tag Value pairs, {terse {Terse: Verbose} ....}
value - The terse part or verbose part of the wanted enumValue
Outputs: None
Returns:
enumValue - The given value if not found; the corresponding enumValue, {Terse: Verbose}, if found

Entity::Verbose

This procedure returns the verbose portion of the enumValue; the portion to the right of the colon.

Inputs:
enumValue - An enum value of form, {Terse:Verbose}
Outputs: None
Returns:
verboseValue - The verbose portion of the enumValue; the portion to the right of the colon.

Entity::Terse

This procedure returns the terse portion of the enumValue; the portion to the left of the colon.

Inputs:
enumValue - An enum value of form, {Terse:Verbose}
Outputs: None
Returns:
terseValue - The terse portion of the enumValue; the portion to the left of the colon.

Entity::Tag

This procedure returns the tag portion of the enumValue.

Inputs:
enumValueList - A list of enum values {terse {Terse: Verbose} ...}
value - The terse and verbose part of the wanted enumValue
Outputs: None
Returns:
tag - The tag value of the wanted enumeration

Entity::EnumMax

This procedure returns a list of the maximum terse and verbose lengths on the given enumList. This is used for user input for view management settings for column width.

Inputs:
enumList - A list of enum Tag Value pairs, {terse {Terse: Verbose} ....}
Outputs: None
Returns:
maxList - [list maxTerseLength maxVerboseLength]

Entity::GetTableList

This procedure returns a list of database tables represented by the attributes in the given objref. It is used by an entity class to determine which tables need to be touched when modifying the database.

  1. For each attribute in objref, find its table by calling Entity::GetAttribute. Add the table to the list if not already on te list.
  2. Return the unique list of tables
Inputs:
class - The entity class to operate on
objref - The array reference that represents the entity object instance.
Outputs: None
Returns:
A table list - A Tcl list of tables represented by the attributes in the object, objref.

Entity::SplitTables

This procedure returns the list of attribute-value pairs that belong to the given database table. If an entity object spans two or more database tables, that object, objref, will contain attributes and values that belong to more than one. This procedure returns an instance that corresponds to the given table. this procedure is used by an entity class when modifying the database since it must update one table at a time. It

  1. Copy the objref oid to a temporary array
  2. For every attribute in the array, objref, load the attribute and value into the temporary array if it belongs to the given table. This is determined by calling Entity::GetAttribute
  3. Return the temporary array instance.
Inputs:
class - The entity class to operate on
objref - The array reference that represents the entity object instance.
table - The table name for which the attributes are to be returned.
Outputs: None
Returns:
array instance - a list of attributes and values that belong to the given table. This can be converted into an object by doing an array set

Entity::BuildWhere

This procedure converts a list of attribute-value pairs, {attr1 value1 attr2 %value2 attr3 !value3 attr4 !value4% attr5 <value5 attr6 >value6 attr7 !>value7} into a where string of the form:

attr1=value1 and attr2 like %value2 and attr3 !=value3 and attr4 not like value4% and attr5<=value5 and attr6 >=value6 and attr7<value7

If a value is proceeded by a "!" sign, as in our example, this translates into a "!=" or a "not like" in the where clause. The wildcard, "%" is accepted anywhere in the value string. Its presence in the string results in a "like" or "not like" match. If the value is preceeded by a "<" or ">", this translates into "<=" or ">=" respectively. If the value is preceeded by "!<" or "!>", this translates into the negation of "<" or ">", namely ">" or "<", respectively. Note that ">" really means ">=", and its negation is "<". This is especially useful for comparing dates. For example,

set oidList [Building::RetrieveOidBy createDate "<function getdate()"]

This will retrieve an oids that have a createDate < the current time. It

  1. Checks for an even number of elements in the attribute-value list,
  2. For each {attribute value} pair in the list, constructs the where substring using Entity::GetAttribute and DbObject::BuildType. It also determines if the operator should be "=", "!=", "like", "not like", <=, >=, <, or >.
  3. Concatenates each where substring together using the "and" operator to build the final where string.
Inputs:
class - The entity class to operate on
argList - A list of attribute-value pairs
Outputs: None
Returns:
whereStr - A where string that is composed from the attribute-value pairs given in the argList. Each attribute-value pair is ANDed together.

Entity::BuildOrder

This procedure builds the body of an "order by" clause (excluding the SQL keywords "order by" from an entity of the given class. It has two forms, in one, the attributes and sorting orders (ascending or descending) are passed as a single list, or alternately, each attribute and sorting order is passed as an individual argument.

More specifically, this procedure:

  1. Computes the argument count, as the list length of the $args list,
  2. Immediately returns a null string for a zero-length argument list,
  3. If the argument count is 1, and the first element of the argument list is non-null, uses eval to call itself recursively with the argument list broken down into individual arguments, returning the result,
  4. Otherwise, if the argument count is odd, throw an error.
  5. Otherwise, the argument count being even, interpret the argument list as {attribute order} pairs, and for each such pair, use Entity::GetAttribute to convert the attribute to a SQL column, then append the column and order string (taken as-is with no conversion) to the order clause list,
  6. Finally, join the order clause list into a string, using a comma and a space as the join string, and return the joined list.
Inputs:
class - The entity class for which an order clause is to be constructed.
args - A single argument comprising a list of pairs of attributes and sorting orders (asc for ascending, or desc for descending). or an even number of arguments comprising alternating attributes and sort directions.
Outputs: None
Returns:
orderClause - a partial order clause (without the "order by" keyword) suitable for passsing to Entity::Query.

Entity::Transition

This procedure is used to bring a finite state machine to its next state given an event. The object that uses this must have the state machine defined in an fsm array in its namespace constructor. e.g. "set MyClass::fsm(initialState, anEvent) {ready MyClass::MakeReady}" would be the state information needed to move from initialState to ready for an event of anEvent. MyClass::MakeReady would be the procedure executed on the state change. If no proc is to be executed, use the word, null, as the procedure name. The attribute, fsmState must be the attribute of the object and obj(fsmState) must be intialized to the beginning state.

Inputs:
class - The entity class that contains the finite state machine.
event - The transitioning event
objref - The object instance to be moved from one state to another.
Outputs:
obj(fsmState) - The new state of the object.
Returns: None

IMPLEMENTATION

namespace eval Entity {
}

EntityCreate

proc EntityCreate {entity} {
   namespace eval $entity {
         lappend this(procedures) Create

      proc Create {objref {selectList {}}} {
         upvar $objref obj
         variable this

         if [catch {Entity::Create $this(class) obj $selectList} result] {
            error "[lindex [info level 0] 0] $result"
         }
      }

   }
}

EntityArrayCopy

proc EntityArrayCopy {entity} {
   namespace eval $entity {
         lappend this(procedures) ArrayCopy

      proc ArrayCopy { objref {selectList {}} } {
         upvar $objref obj
         variable this

         if [catch {set rtn [Entity::ArrayCopy $this(class) obj $selectList]} result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $rtn
      }
   }
}

EntityQuery

proc EntityQuery {entity} {
   namespace eval $entity {
         lappend this(procedures) Query

      proc Query { objref {where {}} {order {}} } {
         upvar $objref obj
         variable this

	 set DbObject [set $this(class)\::this(DbObject)]
         if [catch {$DbObject\::Query $this(class) obj $where $order} result] {
            error "[lindex [info level 0] 0] $result"
         }
      }   

   }
}

EntityNext

proc EntityNext {entity} {
   namespace eval $entity {

         lappend this(procedures) Next
      proc Next {objref} {
         upvar $objref obj
         variable this

	 set DbObject $this(DbObject)

         if [catch {set rtn [$DbObject\::Next $this(class) obj]} result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $rtn
      }

   }
}

EntityInsert

proc EntityInsert {entity} {
   namespace eval $entity {
         lappend this(procedures) Insert

      proc Insert {objref} {
         upvar $objref obj
         variable this

         if [catch {set rtn [Entity::Insert $this(class) obj]} result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $rtn
      }      

   }
}

EntityInsertUpdate

proc EntityInsertUpdate {entity} {
   namespace eval $entity {
         lappend this(procedures) InsertUpdate

      proc InsertUpdate {objref attr value args} {
         upvar $objref obj
         variable this
       
         set argList [list $this(class) obj $attr $value]
         foreach item $args {lappend argList $item}         
         if [catch {
           set rtn [eval Entity::InsertUpdate $argList]
         } result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $rtn    
      }
   }
}

EntityUpdate

proc EntityUpdate {entity} {
   namespace eval $entity {
         lappend this(procedures) Update

      proc Update {objref} {
         upvar $objref obj
         variable this

         if [catch {set rtn [Entity::Update $this(class) obj]} result] {
            error "[lindex [info level 0] 0] $result"
         }
      }     

   }
}

EntityUpdateWhere

proc EntityUpdateWhere {entity} {
   namespace eval $entity {
         lappend this(procedures) UpdateWhere

      proc UpdateWhere {objref attr value args} {
         upvar $objref obj
         variable this

         set argList [list $this(class) obj $attr $value]
         foreach item $args {lappend argList $item}
         if [catch {
               set objList [eval Entity::UpdateWhere $argList] 
         } result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $objList
      }     

   }
}

EntityDelete

proc EntityDelete {entity} {
   upvar #0 $entity\::attr attr

   if [info exists attr(mdt)] {
      namespace eval $entity {
            lappend this(procedures) Delete

         proc Delete {objref} {
            upvar $objref obj
            variable this

            if {[info exists obj(mdt)] == 0 || [string compare $obj(mdt) {}] == 0} {
               error "[lindex [info level 0] 0] Mdt not set, Cannot Delete"
               return
            }

                    #Now delete the object in question
            if [catch {set rtn [Entity::Delete $obj(mdt) obj]} result] {
               error "[lindex [info level 0] 0] $result"
            }

         }
      }
   } else { 
      namespace eval $entity {

            lappend this(procedures) Delete
         proc Delete {objref} {
            upvar $objref obj
            variable this

            if [catch {Entity::Delete $this(class) obj} result] {
               error "[lindex [info level 0] 0] $result"
            }
         }
      }
   }
}

EntityDeleteWhere

proc EntityDeleteWhere {entity} {
     namespace eval $entity {
     lappend this(procedures) DeleteWhere

     proc DeleteWhere {attr value args} {
          variable this

          set argList [list $this(class) $attr $value]
          foreach item $args {lappend argList $item}
          if [catch {eval Entity::DeleteWhere $argList} result] {
             error "[lindex [info level 0] 0] $result"
          }
    }
  }
}

EntityRefresh

proc EntityRefresh {entity} {
   namespace eval $entity {
         lappend this(procedures) Refresh

      proc Refresh {objref} {
         upvar $objref obj
         variable this

         if [catch {set rtn [Entity::Refresh $this(class) obj]} result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $rtn
      }      

   }
}

EntityGetAttribute

proc EntityGetAttribute {entity} {
   namespace eval $entity {

         lappend this(procedures) GetAttribute
      proc GetAttribute {{attribute {}} {property {}} {enumTagList {}} } {
         variable this

         if [catch {set rtn [Entity::GetAttribute $this(class) $attribute $property $enumTagList]} result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $rtn
      }      

   }
}

EntityValue

proc EntityValue {entity} {
   namespace eval $entity {

         lappend this(procedures) Value
      proc Value { oid attr {value {}} } {
         variable this

         if [catch {set value [Entity::Value $this(class) $oid $attr $value]} result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $value
      }

   }
}

EntityRetrieveOidBy

proc EntityRetrieveOidBy {entity} {
   namespace eval $entity {

         lappend this(procedures) RetrieveOidBy
      proc RetrieveOidBy { attr value args } {
         variable this

         set argList [list $this(class) $attr $value]
         foreach item $args {lappend argList $item}
         if [catch {
            set oidList [eval Entity::RetrieveOidBy $argList]
         } result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $oidList
      }
   }
}

EntityRetrieveObjBy

proc EntityRetrieveObjBy {entity} {
   namespace eval $entity {

         lappend this(procedures) RetrieveObjBy
      proc RetrieveObjBy { attr value args } {
         variable this

         set argList [list $this(class) $attr $value]
         foreach item $args {lappend argList $item}
         if [catch {
            set objList [eval Entity::RetrieveObjBy $argList]
         } result] {
            error "[lindex [info level 0] 0] $result"
         }

         return $objList
      }
   }
}

EntityGetListOf

proc EntityGetListOf {entity} {
   namespace eval $entity {
         lappend this(procedures) GetListOf

      proc GetListOf { attr args } {
         variable this

         set argList [list $this(class) $attr]
         foreach item $args {lappend argList $item}

         if [catch {
            set attrList [eval Entity::GetListOf $argList]
         } result] {
            error "[lindex [info level 0] 0] $result"
         }

         return $attrList
      }
   }
}

EntityCount

proc EntityCount {entity} {
   namespace eval $entity {
         lappend this(procedures) Count

      proc Count { {attr *} args } {
         variable this

         set argList [list $this(class) $attr]
	 if {[llength $argList] == 1} {
	     set argList [lindex $argList 0]
         }

         foreach item $args {lappend argList $item}

         if [catch {
            set count [eval Entity::Count $argList]
         } result] {
            error "[lindex [info level 0] 0] $result"
         }

         return $count
      }
   }
}

EntityContainedList

proc EntityContainedList {entity} {
   namespace eval $entity {

         lappend this(procedures) ContainedList
      proc ContainedList { containerOid {selectList {}} } {
         variable this

         if [catch {set containedList [Entity::ContainedList $this(class) \
                        $containerOid $selectList]
            } result] {
               error "[lindex [info level 0] 0] $result"
         }

         return $containedList
      }
   }
}

EntityContainer

proc EntityContainer {entity} {
   namespace eval $entity {
         lappend this(procedures) Container

      proc Container { oid objref } {
         upvar $objref obj
         variable this

         if [catch {
            set rtn [Entity::Container $this(class) $oid obj]
         } result] {
            error "[lindex [info level 0] 0] $result"
         }
         return $rtn
      }
   }
}

EntityRetrieve

proc EntityRetrieve {entity} {
   namespace eval $entity {

            lappend this(procedures) Retrieve
      proc Retrieve { oid objref {selectList {}} } {
            upvar $objref obj
            variable this

            if [catch { set rtn [Entity::Retrieve $this(class) $oid obj $selectList] } result] {
               error "[lindex [info level 0] 0] $result"
            }
            return $rtn
      }
   }
}

EntityMdtRetrieve

proc EntityMdtRetrieve {entity} {
   namespace eval $entity {

            lappend this(procedures) MdtRetrieve
      proc MdtRetrieve { oid objref } {
            upvar $objref obj
            variable this

            if [catch { set rtn [Entity::MdtRetrieve $this(class) $oid obj] } result] {
               error "[lindex [info level 0] 0] $result"
            }
            return $rtn
      }
   }
}

EntityTransition

proc EntityTransition {entity} {
   namespace eval $entity {

            lappend this(procedures) Transition 
      proc Transition { event objref } {
            upvar $objref obj
            variable this

            if [catch { 
               Entity::Transition $this(class) $event obj
            } result] {
               error "[lindex [info level 0] 0] $result"
            }
            return
      }
   }
}

Entity::GetAttribute

proc Entity::GetAttribute { class {attribute {}} {property {}} {enumTagList {}} } {
   upvar #0 $class\::attr attr

   set valueList {}

      #if no attribute is given return the entire set
   if {[string compare $attribute {}] == 0} {
      return [array get attr]
   } else {
               #Does it exist?
      if {[info exists attr($attribute)] == 0} {return {}}

          #If no property is given return the entire attribute instance
      if {[string compare $property {}] == 0} {
            return $attr($attribute)
      } else {
             #Return the property of the attribute
         array set attrArray $attr($attribute)

                  #Does it exist?  If so, return the property value 
         if {[info exists attrArray($property)] == 0} {return {}}

         switch -- $property {
            enum {
               if {[string compare $enumTagList {}] == 0} {
                  return $attrArray($property)
               } else {
                  array set enum $attrArray(enum)
                  switch $enumTagList {
                     tags {return [array names enum]}
                     values {
                        foreach tag [array names enum] {lappend valueList $enum($tag)}
                        return $valueList
                     }
                     default {
                         #enumTagList may be a list
                        foreach tag $enumTagList {
                           if [info exists enum($tag)] {lappend valueList $enum($tag)}
                        }
                        if {[llength $enumTagList] > 1} {
                           return $valueList
                        } else {
                           return [join $valueList]
                        }
                     }
                  }
               }
            } 
            default {return $attrArray($property)}
         }
      }
   }
   return {}
}

Entity::Create

proc Entity::Create {class objref {selectList {}}} {
   upvar $objref obj
   upvar #0 $class\::attr classAttr

   logEntryLS DbgEntryExit "Entering Entity::Create"

   if {[string compare $selectList {}] == 0} {
      set selectList [array names classAttr]
   } else {
         #If given a selectList, always include oid, dt, mdt 
      lappend selectList oid
      if [info exists classAttr(dt)] { lappend selectList dt }
      if [info exists classAttr(mdt)] { lappend selectList mdt }
   } 
   foreach attr $selectList {
      set obj($attr) [GetAttribute $class $attr default]
   }  
   logEntryLS DbgEntryExit "Exiting Entity::Create"
}

Entity::ArrayCopy

proc Entity::ArrayCopy { class objref {selectList {}} } {
   upvar $objref obj
   upvar #0 $class\::attr classAttr

   logEntryLS DbgEntryExit "Entering Entity::ArrayCopy"

       #return the entire list
   if {[string compare $selectList {}] == 0} {
      set selectList [array names classAttr]
   } else {
          #return the list given plus the necessary internals, oid, dt, mdt
      lappend selectList oid
      if [info exists classAttr(dt)] { lappend selectList dt }
      if [info exists classAttr(mdt)] { lappend selectList mdt }
      if [info exists classAttr(coid)] { lappend selectList coid }
   }

   foreach attr $selectList {
      if [info exists obj($attr)] {set tmp($attr) $obj($attr)}
   }
   logEntryLS DbgEntryExit "Exiting Entity::ArrayCopy"
   return [array get tmp]
}

Entity::Insert

proc Entity::Insert {class objref} {
   upvar $objref obj
   upvar #0 $class\::this this

   logEntryLS DbgEntryExit "Entering Entity::Insert"

         #Only begin a transaction if there is more than one table involved
   set updateTableList [GetTableList $this(class) obj]
   set DbObject $this(DbObject)

   if {[llength $updateTableList] > 1} { $DbObject\::Begin }

          #Loop through all of the tables
   set i 1

   foreach table $this(hierarchy) {
      upvar #0 $table\::attr attr

        #Get all attributes belonging to that table
           #array set subobj [SplitTables $this(class) obj $table]
           # Account for tables that whose name differs from the class. 

      if {[llength $this(hierarchy)] == 1} { 
          if {![cequal [lindex $this(hierarchy) 0] $this(table)]} {
	       set holdTable $this(table)
	       set this(table) [lindex [split $this(table) \ ] 0]
               array set subobj [SplitTables $this(class) obj $this(table)]
          } else {
               array set subobj [SplitTables $this(class) obj $table]
	  }
      } else {
            array set subobj [SplitTables $this(class) obj $table]
      } 


            #If mdt exists for this table, ensure it is in the list and set to this object's value
               #This also ignores any value set by the user
      if [info exists attr(mdt)] {
         if {[string compare [GetAttribute $table mdt table] $table] == 0} {
            set subobj(mdt) $this(class)
            set obj(mdt) $this(class) 
         } 
     }

       #If dt exists for this table, ensure it is in the list and set to the next objects value 
     if [info exists attr(dt)] {
        set subobj(dt) [lindex $this(hierarchy) $i]
        set obj(dt) $subobj(dt) 
        incr i
     }

        #If attributes are returned (more than just oid) do the insert
     if {[array size subobj] > 1} {
         if [catch {set obj(oid) [$DbObject\::Insert $table subobj]} result] {
            if {[llength $updateTableList] > 1} { $DbObject\::Rollback }
               error "Entity::Insert $result"
         }
     }
     unset subobj
   }

   if {[llength $updateTableList] > 1} { $DbObject\::Commit }
   logEntryLS DbgEntryExit "Exiting Entity::Insert with oid, $obj(oid)"
   if {[llength $this(hierarchy)] == 1} { 
       if {![cequal [lindex $this(hierarchy) 0] $this(table)]} {
          set this(table) $holdTable
       }
   }
   return $obj(oid)
}

Entity::Update

proc Entity::Update {class objref} {
   upvar $objref obj
   upvar #0 $class\::this this

   logEntryLS DbgEntryExit "Entering Entity::Update"

   set updateTableList [GetTableList $this(class) obj]
   set DbObject $this(DbObject)

   if {[llength $updateTableList] > 1} { $DbObject\::Begin }
   
      #Loop through all of the tables 
   foreach table $this(hierarchy) {
          #Get all attributes belonging to that table 
      if {[llength $this(hierarchy)] == 1} { 
          if {![cequal [lindex $this(hierarchy) 0] $this(table)]} {
	        set holdTable $this(table)
	        set this(table) [lindex [split $this(table) \ ] 0]
                array set subobj [SplitTables $this(class) obj $this(table)]
             } else {
                array set subobj [SplitTables $this(class) obj $table]
	     }
      } else {
          array set subobj [SplitTables $this(class) obj $table]
      } 

           #If attributes are returned (more than just oid) do the insert 
      if {[llength $this(hierarchy)] == 1} { 
          if {![cequal [lindex $this(hierarchy) 0] $this(table)]} {
             set this(table) $holdTable 
	  }
      }

      if [catch {$DbObject\::Update $table subobj} result] {
          if {[llength $updateTableList] > 1} { $DbObject\::Rollback }
          error "Entity::Update $result"
      }
   unset subobj
 } 

 if {[llength $updateTableList] > 1} { $DbObject\::Commit }
 logEntryLS DbgEntryExit "Exiting Entity::Update"
}

Entity::UpdateWhere

proc Entity::UpdateWhere {class objref attr value args} {
   upvar $objref obj
   upvar #0 $class\::this this

   set oidList {}
   set argList [list $attr $value]
   set DbObject  $this(DbObject)

   foreach item $args {lappend argList $item}

   if [ catch {
        set oidList [eval $class\::RetrieveOidBy $argList]
        if {[llength $oidList] > 1} { $DbObject\::Begin }
        foreach oid $oidList {
            set obj(oid) $oid
            $class\::Update obj
        }
   } result ] {
        if {[llength $oidList] > 1} {$DbObject\::Rollback }
        error "Entity::UpdateWhere: $result"
   }

   if {[llength $oidList] > 1} { $DbObject\::Commit }

   return $oidList
}

Entity::Delete

proc Entity::Delete {class objref} {
   upvar $objref obj
   upvar #0 $class\::this this

   logEntryLS DbgEntryExit "Entering Entity::Delete"
 
   set DbObject $this(DbObject)
   $DbObject\::Begin

   foreach table $this(hierarchy) {
      upvar #0 $table\::this parentclass

         #First, check for and delete any containees
   foreach containedclass $parentclass(containedClass) {
      if [info exists $containedclass\::attr(coid)] {
         if [catch {
            foreach containeeList [$containedclass\::ContainedList $obj(oid)] {
               array set containee $containeeList
                     #Call the derived function so redefinition is possible
	              if [info exists containee(mdt)] {
                  $containee(mdt)\::Delete containee
               } else {
	              [set $containedclass\::this(class)]\::Delete containee
	              }
                 unset containee
	           }
         } result] {
            $DbObject\::Rollback
            error "[lindex [info level 0] 0] $result"
         }
      }
   }
          #Now handle the inheritance
      if [catch {$DbObject\::Delete $table obj} result] {
         $DbObject\::Rollback
         error "Entity::Delete $result"
      }
   } 
   
   $DbObject\::Commit 
   
   logEntryLS DbgEntryExit "Exiting Entity::Delete"
}

Entity::DeleteWhere

proc Entity::DeleteWhere {class attr value args} {
   upvar #0 $class\::this this

   set objList {}
   set argList [list $attr $value]
   set DbObject $this(DbObject)
   
   foreach item $args {lappend argList $item}
   if [ catch {
      set objList [eval $class\::RetrieveObjBy $argList]
      if {[llength $objList] > 1 } { $DbObject\::Begin }
      foreach instanceList $objList {
          array set obj $instanceList
          $class\::Delete obj
      }
   } result ] {
       if {[llength $objList] > 1} {$DbObject\::Rollback }
       error "Entity::DeleteWhere: $result"
   }
   if {[llength $objList] > 1} {$DbObject\::Commit }
}

Entity::EnumValue

proc Entity::EnumValue {enumValueList value} {
     # Match for tersevalue | verbosevalue 
     # For terse, match anything beginning(^) with the given value 
     #   followed by ':' 
     # For verbose, match any character that is not ":" 
     #   followed by ": " and ending with value. 
   set enumIndex [lsearch -regexp $enumValueList \
	"^$value: .*\$|^.: $value\$"]
   if { $enumIndex == -1 } {
      return $value
   }
   return [lindex $enumValueList $enumIndex]
}

Entity::Verbose

proc Entity::Verbose {enumValue} {
   regsub {[^:]*: } $enumValue {} verbose
   return $verbose
}

Entity::Tag

proc Entity::Tag {enumValueList enumValue} {

     set enumIndex [lsearch $enumValueList $enumValue]
     incr enumIndex -1

     #Return the tag
     return [lindex $enumValueList $enumIndex]
}

Entity::Terse

proc Entity::Terse {enumValue} {
   regsub -- {[:] .*} $enumValue {} terse
   return $terse
}

Entity::EnumMax

proc Entity::EnumMax {enumList} {
   set maxFriendlyLength 0
   set maxTerseLength 0
   array set enum $enumList
   foreach tag [array names enum] {
       set friendlyLength [string length [Verbose $enum($tag)]]
       if {$maxFriendlyLength < $friendlyLength} { set maxFriendlyLength $friendlyLength }
       set terseLength [string length [Terse $enum($tag)]]
       if {$maxTerseLength < $terseLength} { set maxTerseLength $terseLength }    
   }
   return [list $maxTerseLength $maxFriendlyLength]
}

Entity::Refresh

proc Entity::Refresh {class objref} {
   upvar $objref obj
   upvar #0 $class\::this this

   logEntryLS DbgEntryExit "Entering Entity::Refresh"

   set DbObject $this(DbObject)

   set oidColumn [GetAttribute $class oid column]
   if [ catch {
          $DbObject\::Query $class obj "$oidColumn = $obj(oid)"
          set rtn [$DbObject\::Next $class obj]
      } result] {
          error "Entity::Refresh: $result" 
   }
   logEntryLS DbgEntryExit "Exiting Entity::Refresh"
   return $rtn
}

Entity::GetListOf

proc Entity::GetListOf {class attr args} {
   upvar #0 $class\::this this

   set DbObject $this(DbObject)

   if [catch {
       set where [Entity::BuildWhere $class $args]
       set column [lindex [split [Entity::GetAttribute $class $attr column] .] 1]
       set valueList [$DbObject\::GetListOf $class $attr $where "$column asc "]
   } result] {error "Entity::GetListof: $result"}
   return $valueList
}

Entity::Count

proc Entity::Count {class attr args} {
   upvar #0 $class\::this this

   set DbObject $this(DbObject)

   if [catch {
       set count [$DbObject\::Count $class [Entity::BuildWhere $class $args] $attr]
   } result] {error "Entity::Count: $result"}
   return $count
}

Entity::RetrieveOidBy

proc Entity::RetrieveOidBy {class attr value args} {
   upvar #0 $class\::this this

   set DbObject $this(DbObject)

   set oidList {}
   set where {}

   if [catch {
      set argList [list $attr $value]
      foreach item $args {lappend argList $item}
   } result] {
      error "$result"
   }

   Create $class s oid

   if [catch {
      $DbObject\::Query $class s [Entity::BuildWhere $class $argList] 
      while {[$DbObject\::Next $class s]} {lappend oidList $s(oid)}
   } result] {error "$result"}

   return $oidList
}

Entity::BuildWhere

proc Entity::BuildWhere {class attrList} {
     upvar #0 $class\::this this

     set DbObject $this(DbObject)

     set where {}

     if {([llength $attrList] % 2)} {
        error {list must have an even number of elements}
     }

         #Process each attr-qual pair
     foreach {attribute qualifier} $attrList {
     logEntryLS DebugAll "Processing '$attribute' '$qualifier'."

           #Convert the attributes to raw where components using the SI
           #properties. 
     set whereColumn [Entity::GetAttribute $class $attribute column]
     set attrType [Entity::GetAttribute $class $attribute type]
     if {[string equal {} $whereColumn]} {
         logEntryLS Warning "Entity::BuildWhere $class could not find\
         column for attribute '$attribute', qualifier '$qualifier'."
     }

         #Build the where clause from the list of attributes and their 
         #values
         #Strip off operator indicator, <, >, !, or % and
         #translate to where operator 
     switch -glob $qualifier {
     {!<*} {
             #Strip the !< and convert operator to >  
           set whereValue [$DbObject\::BuildType $attrType \
               [string trimleft $qualifier {!<}]]
           set whereString "$whereColumn > $whereValue"
     }
     {!>*} {
              #String the !> and convert operator to < 
            set whereValue [$DbObject\::BuildType $attrType \
                [string trimleft $qualifier {!>}]]
            set whereString "$whereColumn < whereValue" 
     }
     {!*} {
              #Negating operator ! found - Strip it out 
            set whereValue [$DbObject\::BuildType $attrType \
                [string trimleft $qualifier !]]
               #Check for a % anywhere in the string, but leave token 
               #as part of the where.
            if {[string first % $qualifier] != -1} {
                 #Convert to the proper operator 
               set whereString "$whereColumn Not like $whereValue"
            } else {
               set whereString "$whereColumn != $whereValue"
            }
    } 
    {<*} {
            #Strip the < and convert operator to <= 
          set whereValue [$DbObject\::BuildType $attrType \
              [string trimleft $qualifier <]]
          set whereString "$whereColumn <= whereValue" 
    }
    {>*} {
            #Strip the > and convert operator to >= 
          set whereValue [$DbObject\::BuildType $attrType \
              [string trimleft $qualifier >]]
          set whereString "$whereColumn >= whereValue" 
    }
    default {
          set whereValue [$DbObject\::BuildType $attrType $qualifier] 
           #Check for a % anywhere in the string, but leave token
           #as part of the where. 
          if {[string first % $qualifier] != -1} {
               #convert to the proper operator.
              set whereString "$whereColumn like $whereValue"
          } else {
              set whereString "$whereColumn = $whereValue"
          }
   }
  }
  logEntryLS DebugAll "Entity::BuildWhere whereString\
           '$whereString'. "

       #Append each tag-value where element to the clause. 
  if {[string match $where {}]} {
      set where $whereString
  } else {
      set where "$where and $whereString"
  }
 }
 return $where
}

Entity::BuildOrder

proc Entity::BuildOrder {class args} {
   set argc [llength $args]
   set eMsg {attribute, order list must have an even number of args}

   if {!$argc} {
      return {}
   } elseif {$argc == 1} {
      if {[llength [lindex $args 0]] > 1} {
         return [eval [list Entity::BuildOrder $class] [lindex $args 0]]
      } else {
         error $eMsg
      }
   } elseif {$argc % 2} {
         error $eMsg
   } else {
      set oc {}
      foreach {attr order} $args {
         set col [Entity::GetAttribute $class $attr column]
         lappend oc [list $col $order]
      }
      return " [join $oc {, }] "
   }
}

Entity::RetrieveObjBy

proc Entity::RetrieveObjBy {class attr value args} {
     upvar #0 $class\::this this

     set objList {}

     set DbObject $this(DbObject)
   
     if [catch {
        set argList [list $attr $value]
        foreach item $args {lappend argList $item} 
     } result] {
        error "$result"
     }

     Create $class s

     if [catch {
        $DbObject\::Query $class s [Entity::BuildWhere $class $argList] 
        while {[$DbObject\::Next $class s]} { 
            lappend objList [array get s]
        }
     } result] {error "$result"}

     return $objList
}

Entity::Value

proc Entity::Value {class oid attr {value {}}} {
     upvar #0 $class\::this this

     set DbObject  $this(DbObject)

     Create $class s $attr
     set s(oid) $oid

     if {[string compare $value {}] == 0} {
        if [catch {Refresh $class s} result] { error "Entity::Value: $result"}
           return $s($attr)
        } else {
          if [catch {
             Refresh $class s
             set s($attr) $value
             Update $class s
        } result] { error "Entity::Value: $result"}
        return $value
     }
}

Entity::InsertUpdate

proc Entity::InsertUpdate {class objref attr value args} {
     upvar $objref obj
     upvar #0 $class\::this this

     set DbObject $this(DbObject)

        #Set up the attribute array using the parameter arguments
     if [catch {
        set argList [list $attr $value]
        foreach item $args {lappend argList $item}
        array set attrArray $argList
     } result] {
        error "Entity::InsertUpdate: Parsing the argument list: $result"
     }

     if [catch {
	 set oidList [eval $class\::RetrieveOidBy $argList]
     } result] {error "Entity::InsertUpdate: Retrieving using argument list: $result"}

     if [catch {
         #Found an object
         if {[llength $oidList] == 1} {
             $class\::Update obj
             set tmpoid [lindex $oidList 0]
	     set obj(oid) $tmpoid
	     $class\::Update obj

            #No object found
         } elseif {[llength $oidList] == 0} {
             set tmpoid [$class\::Insert obj]
 
         #More than 1 object found, generate error
         } else {
              error "Entity::InsertUpdate: The given search is not\
		   unique; multiple objects found"
         }
      } result] { error "Entity::InsertUpdate: $result" }

      return $tmpoid
}

Entity::GetTableList

proc Entity::GetTableList { class objref } {
   upvar $objref obj

   logEntryLS DbgEntryExit "Entering Entity::GetTableList"

   set tableList {}
   foreach attr [array names obj] {

          #Skip the oid
      if {[string compare oid $attr] == 0} {continue}

      set table [Entity::GetAttribute $class $attr table]
      if {[lsearch -exact $tableList $table] == -1} {
         lappend tableList $table
      }
   }
   logEntryLS DbgEntryExit "Exiting Entity::GetTableList with tableList. $tableList"
   return $tableList
}

Entity::SplitTables

proc Entity::SplitTables { class objref table } {
   upvar $objref obj

   logEntryLS DbgEntryExit "Entering Entity::SplitTables"

   set tmp(oid) $obj(oid)
   foreach attr [array names obj] {

          #Skip the oid
      if {[string compare oid $attr] == 0} {continue}

      if {[string compare [Entity::GetAttribute $class $attr table] $table] == 0} {
         set tmp($attr) $obj($attr)
      }
   }
   logEntryLS DbgEntryExit "Exiting Entity::SplitTables"
   return [array get tmp]
}

Entity::ContainedList

proc Entity::ContainedList { class containerOid {selectList {}} } {
     upvar #0 $class\::attr attr
     upvar #0 $class\::this this

     set DbObject $this(DbObject)

     set containedList {}
     Entity::Create $class tmp $selectList
     set coidColumn [$class\::GetAttribute coid column]
     $DbObject\::Query $class tmp "$coidColumn = $containerOid"

     while {[$DbObject\::Next $class tmp]} {
        lappend containedList [array get tmp]
     }

     return $containedList
}

Entity::Container

proc Entity::Container {class oid objref} {
   upvar $objref obj
   upvar #0 $class\::this this

   set rtn 0

   if [catch {
      set coid [Entity::Value $class $oid coid]
      if {![string match $coid {}]} {
         set rtn [Entity::MdtRetrieve $this(container) $coid obj]
      } else { error "Entity::Container: Object $oid not found"}
   } result] {error "entity::Container:$result"}
   return $rtn
}

Entity::Retrieve

proc Entity::Retrieve { class oid objref {selectList {}} } {
     upvar $objref obj
     upvar #0 $class\::this this

     set DbObject this(DbObject)

     if [catch {
        Create $class obj $selectList
        set obj(oid) $oid
        set rtn [Refresh $class obj]
     } result] { error "Entity::Retrieve:$result" }

     return $rtn
}

Entity::MdtRetrieve

proc Entity::MdtRetrieve { class oid objref } {
   upvar $objref obj

   if [catch {
      set rtn [Entity::Retrieve $class $oid obj]
      # Check for successful retrieve
      if {$rtn == 1 } {
          if {[info exists obj(mdt)]} {
              if {[string compare $obj(mdt) $class] != 0} {
                  # A most derived class exists for this base class
                  eval [$obj(mdt)Init]
                  set rtn [$obj(mdt)\::Retrieve $oid obj]
              }
          }
      }
   } result] { error "$result" }
   return $rtn
}

Entity::Transition

proc Entity::Transition { class event objref } {
     upvar $objref obj
     LC::logArray DebugAll obj

     if {[catch {
	   set priorfsmState $obj(fsmState)
	   set tag [Entity::Tag [$class\::GetAttribute fsmState enum] " $obj(fsmState)"]
	   LC::logEntry DebugAll "tag"
	   set fsmEntry [set $class\::fsm($tag,$event)]
     } result]} {
       LC:logEntry Error "No event $event for state [Entity::Verbose $obj(fsmState)] found. "
       error "No event $event for state [Entity::Verbose $obj(fsmState)] found."
     else {
	LC::logEntry DebugAll "Old State: $obj(fsmState)"

        if {[catch {
	      # Execute the action if a proc is specified 
           if {![string equal [lindex $fsmEntry 1] NULL]} {
              LC::logEntry Debug "Executing [lindex $fsmEntry 1]"
	      [lindex $fsmEntry 1] obj
	      $class\::Refresh obj
           }
        } result]} {
	   error $result
        } else {
	    # Bring obj to next state 
	    set obj(fsmState)  [$class\::GetAttribute fsmState enum [lindex $fsmEntry 0]]
	    if {![string equal $priorFsmState $obj(fsmState]} {
	       $class\::Value $obj(oid) priorFsmState $priorFsmState
            }
            LC::logEntry Debug "New State: $obj(fsmState)"
	    $class\::Value $obj(oid) fsmState $obj(fsmState)
        }
     }
   }
}

EXAMPLES

NOTES

WARNINGS

SEE ALSO


AUTHORS

by Maureen G. McCarthy & Tim L. Eshelman