Developer Resource - Model Map

HTTP Requests for models are powered through Dovetail's Model Map engine.

Model Map Files

Model Map Files are XML files that define:

They are located in the $agent\source\Web\Models\ directory and sub-directories. The filename format follows a convention of *.map.config

Existing model map files can be modified, and new ones added.

Baseline partial maps can be over-ridden using model map override files. This allows customization without modifying the baseline files.

Model Map File Format

<model name="" entity="">
  <query from="" type="">
    <addProperty key="" field="" dataType="" propertyType="" />
    <addProperty key="" field="" dataType="" />
    <addProperty key="">
      <addTransform name="">
        <addArgument name="" value="" />
        <addArgument name="" property="" />
      </addTransform>
    </addProperty>

    <traverseRelation type="" field="" table="" targetField="">
      <addProperty key="" field="" dataType="" />
    </traverseRelation>

    <traverseRelation name="">
      <addProperty key="" field="" dataType="" />
    </traverseRelation>

    <addMappedProperty key="">
      <traverseRelation name="">
        <addProperty key="" field="" dataType="" />
      </traverseRelation>
    </addMappedProperty>

    <addMappedCollection key="">
      <traverseRelation name="">
        <addProperty key="" field="" dataType="" />
      </traverseRelation>
    </addMappedCollection>

    <addPartial name="" />
  </query>
</model>

Example Model Map File

The following is an example of a model map file for retrieving basic information about a Case:

<model name="case" entity="Case">
  <query from="qry_case_view" type="view">
    <addProperty key="databaseIdentifier" field="elm_objid" dataType="int" />
    <addProperty key="id" field="id_number" dataType="string" propertyType="identifier" />
    <addProperty key="title" field="title" dataType="string" />

    <addProperty key="caseType" field="type" dataType="string">
      <addTransform name="localizedListItem">
        <addArgument name="listName" value="Case Type" />
        <addArgument name="listValue" property="caseType" />
      </addTransform>
    </addProperty>

    <traverseRelation type="adhoc" field="elm_objid" table="case" targetField="objid">
      <addProperty key="created" field="creation_time" dataType="dateTime" />
      <addProperty key="lastModified" field="modify_stmp" dataType="dateTime" />
      <addProperty key="altFirstName" field="alt_first_name" dataType="string" />
      <addProperty key="altLastName" field="alt_last_name" dataType="string" />
      <addProperty key="altPhoneNum" field="alt_phone_num" dataType="string" />
      <addProperty key="altEmail" field="alt_e_mail" dataType="string" />
      <addProperty key="ccList1" field="cclist1" dataType="string" />
      <addProperty key="cclist2" field="cclist2" dataType="string" />
    </traverseRelation>
  </query>
</model>

XML Reference

<model>

The <model> element is the top level element that defines the XML as a model map. This element is required.

Attribute Name Description
name A unique name used to retrieve the map from the IModelBuilder interface. Must be unique across all maps.
entity This optional attribute is used to indicate the base object type that the show model is related to. This is used in Agent's entity link conventions. Available entities include: Account, Case, ChangeRequest, Contact, Contract, Employee, PartRequestDetail, PartRequestHeader, Site, SitePart, Solution, Subcase
Child Nodes
<query>

<query>

The <query> element is a child of the <model> element. The <query> element contains all of the information required to build the clarify generic. This element is required.

Attribute Name Description
from The root table or view to be used for the query.
type "view" or "table" to indicate the type of clarify object being queried.
Child Nodes
<addProperty>
<traverseRelation>
<addMappedProperty>
<addMappedCollection>
<addPartial>
<addProperty>

The <addProperty> element is a child of the <query>, <addMappedProperty>, <addMappedCollection>, or <traverseRelation> elements. The <addProperty> element defines a property on the model that is being constructed.

Attribute Name Description
key Unique Identifier
field Optional. The database column that will be retrieved from the Clarify generic row
dataType Optional. int, string, bool, dateTime, float, decimal
propertyType Optional. Valid values are identifier.
Child Nodes
<addTransform>
<addTransform>

The <addTransform> element is a child of the <addProperty> element. The <addTransform> element specifies the transform to use to resolve the value of the property.

Attribute Name Description
name Name of the transform to use. See Transforms for a list of out-of-the-box transforms and information on creating your own.
Child Nodes
<addArgument>
<addArgument>

The <addArgument> element is a child of the <addTransform> element. The <addArgument> element is used to add an argument that is made available to the transform. See Transforms for a list of out-of-the-box transforms and information on creating your own.

Attribute Name Description
name The name of the argument. This is case-sensitive as specified by the individual transform being used.
value Optional. This attribute specifies the value to be supplied to the argument.
property Optional. This attribute specifies that the value of the argument should be retrieved from the specified property within the current scope.

The value and property attributes are mutually exclusive. One of these attributes must be specified but not both.

<traverseRelation>

The <traverseRelation> element is a child of the <query>, <addMappedProperty>, <addMappedCollection>, or <traverseRelation> elements. The <traverseRelation> element defines a traversal through Clarify generics.

Attribute Name Description
name The name of the relation to traverse.
type This attribute must be set to adhoc if the join is being created dynamically (e.g., from a view to the base table).
field The field being used to initiate the adhoc join. This is required if type is set to adhoc.
table The target table of the adhoc join. This is required if type is set to adhoc.
targetField The target field of the adhoc join. This is required if type is set to adhoc.
Child Nodes
<where>
<addProperty>
<traverseRelation>
<addMappedProperty>
<addMappedCollection>
<addPartial>
<where>

The <where> element is a child of the <traverseRelation> element. The <where> element is used to add Clarify generic filters for its parent <traverseRelation> element.

The where clauses are children of the <where> element.

Type Description
filter Used as the operator in the where clause for the field, i.e. greaterThanOrEqual
values Attributes specified in the dynamic filter element are aggregated and passed into the corresponding IFilterPolicy implementation.
<model>
  <query>
    <traverseRelation>
      <where>
        <notEqual field="objid" value="-2" dataType="int" />
      </where>
    </traverseRelation>
  </query>
</model>

Available filters:

<equals>

Attribute Name Description
field The field to filter by.
value The value of the filter.
dataType The data type of the filter value. int, string, bool, dateTime, float, decimal

<notEqual>

Attribute Name Description
field The field to filter by.
value The value of the filter.
dataType The data type of the filter value. int, string, bool, dateTime, float, decimal

<addMappedProperty>

The <addMappedProperty> element is a child of the <query>, <addMappedProperty>, <addMappedCollection>, or <traverseRelation> elements.

The <addMappedProperty> element defines a nested object on the model that is being constructed.

Attribute Name Description
key Unique Identifier.

Note: If you traversing a relation to retrieve the mapped property, the <traverseRelation> element must be a child of the <addMappedProperty> element.

Child Nodes
<addProperty>
<traverseRelation>
<addMappedProperty>
<addMappedCollection>
<addPartial>

<addMappedCollection>

The <addMappedCollection> element is a child of the <query>, <addMappedProperty>, <addMappedCollection>, or <traverseRelation> elements.

The <addMappedCollection> element defines a nested array on the model that is being constructed.

Attribute Name Description
key Unique Identifier.

Note: If you traversing a relation to retrieve the mapped collection, the <traverseRelation> element must be a child of the <addMappedCollection> element.

Child Nodes
<addProperty>
<traverseRelation>
<addMappedProperty>
<addMappedCollection>
<addPartial>

<addPartial>

The <addPartial> element is a child of the <query>, <addMappedProperty>, <addMappedCollection>, or <traverseRelation> elements.

The <addPartial> element imports a subset of instructions defined in a separate file. See Partials for additional information.

Attribute Name Description
name Unique Identifier.

Any additional attributes specified in the <addPartial> element are made available to the partial as Variables.

Partials

Partial map files are model maps that provide a subset of instructions that are reusable across maps.

They are located in the $agent\source\Web\Models\partials directory and sub-directories. The filename format follows a convention of *.partial.config

Existing partial map files can be modified, and new ones added.

Baseline partial maps can be over-ridden using model map override files. This allows customization without modifying the baseline files.

Transforms

Transforms are C# functions used to transform data (or provide external data)

Available transforms

1. stringConcat

Aggregates all arguments prefixed with arg (e.g., "arg0", "arg1") and concatenates the values.

<addTransform name="stringConcat">
  <addArgument name="arg0" value="Hello" />
  <addArgument name="arg1" value="," />
  <addArgument name="arg2" value=" " />
  <addArgument name="arg3" value="World" />
  <addArgument name="arg4" value="!" />
</addTransform>

2. isEqual

Returns a boolean value of the comparison.

Argument Name Description
field The name of the property to compare
value The value to compare against
<addTransform name="isEqual">
  <addArgument name="field" value="myPropertyName" />
  <addArgument name="value" value="-1" dataType="int" />
</addTransform>

3. sqlCount

Returns the scalar value of a SQL count statement.

Argument Name Description
table The name of the table to query against
relation The name of the column to filter on
objid The value to compare against
<addTransform name="sqlCount">
  <addArgument name="table" value="subcase" />
  <addArgument name="relation" value="subcase2case" />
  <addArgument name="objid" property="databaseIdentifier" />
</addTransform>

This would execute something like the following query: SELECT COUNT(1) FROM table_subcase where subcase2case = 268436288

4. executeScalar

Returns the scalar value of a SQL statement.

Argument Name Description
sql The sql query to execute
dataType The returned dataType of the sql statement

SQL parameters can be added by prefixing arguments with param..

<addTransform name="executeScalar">
  <addArgument name="sql" value="SELECT Count(*) FROM table_demand_hdr where caseinfo2case = {0} AND request_status = 'Open'" />
  <addArgument name="dataType" value="int" />
  <addArgument name="param.caseinfo2case" property="databaseIdentifier" />
</addTransform>

5. localizedListItem

Localizes the list value from the list by value.

Argument Name Description
listName The name of the list
listValue Value of the list item
<addTransform name="localizedListItem">
  <addArgument name="listName" value="Case Type" />
  <addArgument name="listValue" property="caseType" />
</addTransform>

6. localizedListItemByRank

Localizes the list value from the list by rank.

Argument Name Description
listName The name of the list
rank Rank of the list item
<addTransform name="localizedListItemByRank">
  <addArgument name="listName" value="User Status" />
  <addArgument name="rank" property="statusCode" />
</addTransform>

7. localizedListItemByObjId

Localizes the list value from the list by objid.

Argument Name Description
listName The name of the list
objId Objid of the list item
<addTransform name="localizedListItemByObjId">
  <addArgument name="listName" value="My List" />
  <addArgument name="objId" property="databaseIdentifier" />
</addTransform>

Custom Transforms

To create your own custom transform, simply implement the IMappingTransform interface. The TransformContext argument of the execute method provides access to the currently scoped model data instance, as well as the TransformArguments. Below is an example of a simple transform that performs a ToUpper() on the provided string value:

public class ToUpperTransform : IMappingTransform
{
  public object Execute(TransformContext context)
  {
    var input = context.Arguments.Get<string>("input"); // This retrieves the argument with the name "input"
    return input.ToUpper();
  }
}

This transform automatically becomes available as toUpper (case insensitive). If you want more control over the name of the transform, you can decorate your custom transform class with the TransformAliasAttribute.

Variables

Variables are placeholders that get dynamically resolved through C# functions.

Default Variables

  1. sessionUserId This value gets resolved as the objid of the current SDK user.

  2. sessionUserName This value gets resolved as the login name of the current SDK user.

Scoped data

You can also pass data from the currently scoped model data instance using the syntax: {this.propertyName}. This would pass the current value of propertyName as the variable value.

See Scoping for additional information.

Custom Variables

To create your own variable, simply implement the IMappingVariable interface. The following as an example of a variable that provides a random GUID value:

public class RandomVariable : IMappingVariable
{
  public bool Matches(VariableExpansionContext context)
  {
    return context.Key.EqualsIgnoreCase("random");
  }

  public object Expand(VariableExpansionContext context)
  {
    return Guid.NewGuid().ToString();
  }
}

Variables are made available via the IMappingVariableSource interface. To make your variable available, you can implement this interface and provide your variable (or use dependency injection to return all variables). Variables are only created once (singleton). If you need access to services, you can retrieve them from the VariableExpansionContext.

Scoping

During the populating of data in an instance of ModelData, the ModelBuilder constructs data and transforms from the bottom-up. Let's examine our example model map:

<model name="case" entity="Case">
  <query from="qry_case_view" type="view">
    <addProperty key="databaseIdentifier" field="elm_objid" dataType="int" />
    <addProperty key="id" field="id_number" dataType="string" propertyType="identifier" />
    <addProperty key="title" field="title" dataType="string" />

    <addProperty key="caseType" field="type" dataType="string">
      <addTransform name="localizedListItem">
        <addArgument name="listName" value="Case Type" />
        <addArgument name="listValue" property="caseType" />
      </addTransform>
    </addProperty>

    <traverseRelation type="adhoc" field="elm_objid" table="case" targetField="objid">
      <addProperty key="created" field="creation_time" dataType="dateTime" />
      <addProperty key="lastModified" field="modify_stmp" dataType="dateTime" />
      <addProperty key="altFirstName" field="alt_first_name" dataType="string" />
      <addProperty key="altLastName" field="alt_last_name" dataType="string" />
      <addProperty key="altPhoneNum" field="alt_phone_num" dataType="string" />
      <addProperty key="altEmail" field="alt_e_mail" dataType="string" />
      <addProperty key="ccList1" field="cclist1" dataType="string" />
      <addProperty key="cclist2" field="cclist2" dataType="string" />
    </traverseRelation>
  </query>
</model>

The construction of the ModelData instance would go as follows:

  1. databaseIdentifier gets populated
  2. id gets populated
  3. title gets populated
  4. The caseType property would be populated with the value from the type column
  5. The properties defined in the <traverseRelation> element would be populated
  6. The localizedListItem transform fires

In this case, the properties defined in the traverseRelation element are being added to the root ModelData instance.

When a mapped property or collection is used, a new ModelData is created and is available in the TransformContext for transforms. It's important to note that because the values are built from the bottom up, the parent values are not available.