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:
- what tables/views are being queried
- joins
- what properties are projected to the response
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
sessionUserId
This value gets resolved as the objid of the current SDK user.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:
- databaseIdentifier gets populated
- id gets populated
- title gets populated
- The caseType property would be populated with the value from the
type
column - The properties defined in the
<traverseRelation>
element would be populated - 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.