TDS Grid
A PCF control retrieves grid data via TDS endpoint using SQL query
Purpose
This PCF control is available in Model-driven App only.
The Apps Gallery TDS Grid PCF control retrieves data via Dataverse TDS SQL query. It is more flexible and powerful in comparison to the normal FetchXML based grids.
FetchXML is great, but it has its own limitations:
- Unable to combine data from multiple unrelated tables;
- 10 link-entities per query, and more than 3 nested link-entities;
- Cannot use OR conditions that span across multiple tables;
- No direct column to column comparison;
- No right outer joins.
The Dataverse TDS SQL query can overcome these limitations. The only downside is that whoever is configuring this PCF control will need to know SQL and how to query Dataverse data via TDS endpoint, or have a developer to help out.
Important Please make sure Enable TDS endpoint setting is turned on in your Dataverse environment.
Key Features
- Executes SQL query you provided in the PCF control property.
- Respects current user's permission in Dataverse.
- Supports server-side paging, paging sizes are 250 and 500.
- Grouping of a single column.
- Supports lookup fields, the SQL query will need to return the id and name columns of the lookup field.
- Double clicking the row or single click on the primary column to do directly to the record.
- Create New button(s) to open main form or quick create form.
- This is a Readonly grid, there is no inline editing, not yet!
PCF Control Properties
| Property | Required | Type | Purpose |
|---|---|---|---|
Grid Holder Text Field | Yes | Bound SingleLine.Text | Placeholder field used to place the control on a form. The control does not write an output value to this field, you can set the length to 1. |
SQL Command | Yes | Input | The SQL query you want the control to execute. |
SQL Parameters | No | Input | JSON array that maps SQL parameter names to primary entity record values. |
Layout Json | Yes | Input | JSON array that defines grid columns, display values, record links, and grouping. |
New Items Json | Yes | Input | JSON array that defines create button(s) in the command bar. |
Page Size | Yes | Options | Initial page size. Supported values are 250 and 500; default is 250. |
Grid Holder Text Field
Use any single-line text column to place the PCF control on a model-driven form.
Notes:
- This field is only a host placeholder.
- The field does not need to contain any value, and the control will not output any value into it.
- The length of this field can be set to 1.
TDS SQL Command
This property requires the SQL query to retrieve grid rows. When the query is executed, it respects current sign-in user's permission in Dataverse.
Example:
Select contactid, firstname, lastname, emailaddress1, telephone1, gendercodename, birthdate, parentcustomerid, parentcustomeridname
From Contact
Where parentcustomerid = @parm1
SQL Parameters
This property defines parameter substitutions for SQL Command. Each entry maps a SQL parameter name to the primary entity record's ID or to an attribute of it.
Example 1:
[
{
"ParameterName": "@parm1",
"AttributeName": "{{recId}}"
}
]
Or example 2:
[
{
"ParameterName": "@parm1",
"AttributeName": "{{recId}}"
},
{
"ParameterName": "@parm2",
"AttributeName": "{{ag_segmentgroup}}"
}
]
Supported mapping behavior:
{{recId}}resolves to the primary entity record's ID. For example, if this PCF control is loaded on an account, {{recId}} will be resolved to the account record's GUID.- {{ag_segmentgroup}} is a column called ag_segmentgroup of the primary entity record, so it will be resolved to column ag_segmentgroup's value.
- String and GUID values are wrapped in single quotes, with embedded single quotes escaped.
- Number values are inserted as numbers.
- Boolean values are inserted as
1or0. - Missing values are inserted as
NULL.
Example after substitution:
where [parentcustomerid] = '53e78af5-ca9f-f011-bbd3-000d3acbf47d'
Layout Json
This property defines the grid columns, displayed values, record hyperlinks, and optional grouping behavior.
Example:
[
{
"DisplayName": "First Name",
"ColumnValue":{
"Type":"Primary",
"Value": "{{firstname}}",
"EntityName": "contact",
"EntityId": "{{contactid}}"
}
},
{
"DisplayName": "Last Name",
"ColumnValue":{
"Type":"Value",
"Value": "{{lastname}}"
}
},
{
"DisplayName": "Email",
"ColumnValue":{
"Type":"Value",
"Value": "{{emailaddress1}}"
}
},
{
"DisplayName": "Phone Number",
"ColumnValue":{
"Type":"Value",
"Value": "{{telephone1}}"
}
},
{
"DisplayName": "Gender",
"ColumnValue":{
"Type":"Value",
"Value": "{{gendercodename}}"
},
"GroupByColumn": true,
"DisplayGroupByColumn": false
},
{
"DisplayName": "Birthdate",
"ColumnValue":{
"Type":"Value",
"Value": "{{birthdate}}"
}
},
{
"DisplayName": "Parent Account",
"ColumnValue":{
"Type":"Lookup",
"Value": "{{parentcustomeridname}}",
"EntityName": "account",
"EntityId": "{{parentcustomerid}}"
}
}
]
Column properties:
| Property | Description |
|---|---|
DisplayName | Column header text shown in the grid. |
ColumnValue.Type | One of Primary, Value, or Lookup. |
ColumnValue.Value | Text or a placeholder expression used for the cell value. |
ColumnValue.EntityName | Required for Primary and Lookup; resolves to the Dataverse table logical name. |
ColumnValue.EntityId | Required for Primary and Lookup; resolves to the Dataverse row ID. |
GroupByColumn | When true, groups the current page of rows by this column. If multiple columns set it, the last one wins. |
DisplayGroupByColumn | When true, keeps the group-by column visible in the grid. By default, a group-by column is hidden. |
ColumnValue types:
Primary: Displays the value as a link to the record. Double-clicking a row and clicking the primary column both open the record main form.Lookup: Displays the value as a link to the related record. Clicking the link will navigate to the related record.Value: Displays the resolved value as plain grid content. Boolean values display as icons.
Placeholder behavior:
- Use
{{ColumnAlias}}to read a value from the SQL result row. - If the entire value is one placeholder, the original JSON value type is preserved. This allows booleans and numbers to render correctly.
- If a value combines text and placeholders, the result is rendered as a string.
Example combined template:
{
"DisplayName": "Summary",
"ColumnValue": {
"Type": "Value",
"Value": "{{ActivityType}}: {{Name}}"
}
}
New Items Json
This property defines the command bar actions for creating new Dataverse records from the grid.
Example with multiple create actions:
[
{
"DisplayText": "Contact",
"AltText": "Add a new Contact",
"EntityLogicalName": "contact",
"UseQuickCreate": true,
"createFromCurrentEntity": true
},
{
"DisplayText": "Lead",
"AltText": "Add a new Lead",
"EntityLogicalName": "lead",
"UseQuickCreate": true,
"createFromCurrentEntity": true
}
]
New item properties:
| Property | Description |
|---|---|
DisplayText | Text shown for the create action. |
AltText | Tooltip text for the action. |
EntityLogicalName | Dataverse table logical name to create. |
UseQuickCreate | When true, opens the table's quick create form if available. |
createFromCurrentEntity | When true, passes the primary entity record as the source entity for create-from behavior (relationship mappings). |
Rendering behavior:
- If one item is configured, the command bar shows a single primary button using that item's
DisplayText. - If multiple items are configured, the command bar shows a primary split button labelled
New. The primary button opens the first configured item, and the menu lists all configured items. - If the JSON is empty or invalid, no create action is shown.
Page Size
This property controls the initial number of records requested per page.
Supported values:
250
500
Changing sort or page size resets the grid to page 1.