TableOperations Class
Namespace for table-level metadata operations.
Accessed via client.tables. Provides operations to create, delete,
inspect, and list Dataverse tables, as well as add and remove columns.
Example:
client = DataverseClient(base_url, credential)
# Create a table
info = client.tables.create(
"new_Product",
{"new_Price": "decimal", "new_InStock": "bool"},
solution="MySolution",
)
# List tables
tables = client.tables.list()
# Get table info
info = client.tables.get("new_Product")
# Add columns
client.tables.add_columns("new_Product", {"new_Rating": "int"})
# Remove columns
client.tables.remove_columns("new_Product", "new_Rating")
# Delete a table
client.tables.delete("new_Product")
Constructor
TableOperations(client: DataverseClient)
Parameters
| Name | Description |
|---|---|
|
client
Required
|
The parent DataverseClient instance. |
Methods
| add_columns |
Add one or more columns to an existing table. Example:
|
| create |
Create a custom table with the specified columns. |
| create_alternate_key |
Create an alternate key on a table. Alternate keys allow upsert operations to identify records by one or
more columns instead of the primary GUID. After creation the key is
queued for index building; its status will
transition from |
| create_lookup_field |
Create a simple lookup field relationship. This is a convenience method that wraps create_one_to_many_relationship for the common case of adding a lookup field to an existing table. |
| create_many_to_many_relationship |
Create a many-to-many relationship between tables. This operation creates a many-to-many relationship and an intersect table to manage the relationship. |
| create_one_to_many_relationship |
Create a one-to-many relationship between tables. This operation creates both the relationship and the lookup attribute on the referencing table. |
| delete |
Delete a custom table by schema name. Warning This operation is irreversible and will delete all records in the table along with the table definition. Example:
|
| delete_alternate_key |
Delete an alternate key by its metadata ID. Warning Deleting an alternate key that is in use by upsert operations will cause those operations to fail. This operation is irreversible. Example:
|
| delete_relationship |
Delete a relationship by its metadata ID. Warning Deleting a relationship also removes the associated lookup attribute for one-to-many relationships. This operation is irreversible. Example:
|
| get |
Get basic metadata for a table if it exists. Example:
|
| get_alternate_keys |
List all alternate keys defined on a table. |
| get_relationship |
Retrieve relationship metadata by schema name. Example:
|
| list |
List all non-private tables in the Dataverse environment. By default returns every table where Example:
|
| list_columns |
List all attribute (column) definitions for a table. Example:
|
| list_relationships |
List all relationship definitions in the environment. Example:
|
| list_table_relationships |
List all relationships for a specific table. Combines one-to-many, many-to-one, and many-to-many relationships
for the given table by querying
Example:
|
| remove_columns |
Remove one or more columns from a table. Example:
|
add_columns
Add one or more columns to an existing table.
Example:
created = client.tables.add_columns(
"new_MyTestTable",
{"new_Notes": "string", "new_Active": "bool"},
)
print(created) # ['new_Notes', 'new_Active']
add_columns(table: str, columns: Dict[str, Any]) -> List[str]
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
|
columns
Required
|
Mapping of column schema names (with customization prefix) to their types. Supported types are the same as for create. |
Returns
| Type | Description |
|---|---|
|
Schema names of the columns that were created. |
Exceptions
| Type | Description |
|---|---|
|
If the table does not exist. |
create
Create a custom table with the specified columns.
create(table: str, columns: Dict[str, Any], *, solution: str | None = None, primary_column: str | None = None, display_name: str | None = None) -> TableInfo
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table with customization prefix
(e.g. |
|
columns
Required
|
Mapping of column schema names (with customization
prefix) to their types. Supported types include |
|
solution
Required
|
Optional solution unique name that should own the new table. When omitted the table is created in the default solution. |
|
primary_column
Required
|
Optional primary name column schema name with
customization prefix (e.g. |
|
display_name
Required
|
Human-readable display name for the table
(e.g. |
Keyword-Only Parameters
| Name | Description |
|---|---|
|
solution
|
Default value: None
|
|
primary_column
|
Default value: None
|
|
display_name
|
Default value: None
|
Returns
| Type | Description |
|---|---|
|
Table metadata with |
Exceptions
| Type | Description |
|---|---|
|
If table creation fails or the table already exists. |
Examples
Create a table with simple columns:
from enum import IntEnum
class ItemStatus(IntEnum):
ACTIVE = 1
INACTIVE = 2
result = client.tables.create(
"new_Product",
{
"new_Title": "string",
"new_Price": "decimal",
"new_Status": ItemStatus,
},
solution="MySolution",
primary_column="new_ProductName",
display_name="Product",
)
print(f"Created: {result['table_schema_name']}")
create_alternate_key
Create an alternate key on a table.
Alternate keys allow upsert operations to identify records by one or
more columns instead of the primary GUID. After creation the key is
queued for index building; its status will
transition from "Pending" to "Active" once the index is ready.
create_alternate_key(table: str, key_name: str, columns: List[str], *, display_name: str | None = None, language_code: int = 1033) -> AlternateKeyInfo
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
|
key_name
Required
|
Schema name for the new alternate key
(e.g. |
|
columns
Required
|
List of column logical names that compose the key
(e.g. |
|
display_name
Required
|
Display name for the key. Defaults to
|
|
language_code
Required
|
Language code for labels. Defaults to 1033 (English). |
Keyword-Only Parameters
| Name | Description |
|---|---|
|
display_name
|
Default value: None
|
|
language_code
|
Default value: 1033
|
Returns
| Type | Description |
|---|---|
|
Metadata for the newly created alternate key. |
Exceptions
| Type | Description |
|---|---|
|
If the table does not exist. |
|
|
If the Web API request fails. |
Examples
Create a single-column alternate key for upsert:
key = client.tables.create_alternate_key(
"new_Product",
"new_product_code_key",
["new_productcode"],
display_name="Product Code",
)
print(f"Key ID: {key.metadata_id}")
print(f"Columns: {key.key_attributes}")
create_lookup_field
Create a simple lookup field relationship.
This is a convenience method that wraps create_one_to_many_relationship for the common case of adding a lookup field to an existing table.
create_lookup_field(referencing_table: str, lookup_field_name: str, referenced_table: str, *, display_name: str | None = None, description: str | None = None, required: bool = False, cascade_delete: str = 'RemoveLink', solution: str | None = None, language_code: int = 1033) -> RelationshipInfo
Parameters
| Name | Description |
|---|---|
|
referencing_table
Required
|
Logical name of the table that will have the lookup field (child table). |
|
lookup_field_name
Required
|
Schema name for the lookup field
(e.g., |
|
referenced_table
Required
|
Logical name of the table being referenced (parent table). |
|
display_name
Required
|
Display name for the lookup field. Defaults to the referenced table name. |
|
description
Required
|
Optional description for the lookup field. |
|
required
Required
|
Whether the lookup is required. Defaults to |
|
cascade_delete
Required
|
Delete behavior ( |
|
solution
Required
|
Optional solution unique name to add the relationship to. |
|
language_code
Required
|
Language code for labels. Defaults to 1033 (English). |
Keyword-Only Parameters
| Name | Description |
|---|---|
|
display_name
|
Default value: None
|
|
description
|
Default value: None
|
|
required
|
Default value: False
|
|
cascade_delete
|
Default value: RemoveLink
|
|
solution
|
Default value: None
|
|
language_code
|
Default value: 1033
|
Returns
| Type | Description |
|---|---|
|
Relationship metadata with |
Exceptions
| Type | Description |
|---|---|
|
If the Web API request fails. |
Examples
Create a simple lookup field:
result = client.tables.create_lookup_field(
referencing_table="new_order",
lookup_field_name="new_AccountId",
referenced_table="account",
display_name="Account",
required=True,
cascade_delete=CASCADE_BEHAVIOR_REMOVE_LINK,
)
print(f"Created lookup: {result.lookup_schema_name}")
create_many_to_many_relationship
Create a many-to-many relationship between tables.
This operation creates a many-to-many relationship and an intersect table to manage the relationship.
create_many_to_many_relationship(relationship: ManyToManyRelationshipMetadata, *, solution: str | None = None) -> RelationshipInfo
Parameters
| Name | Description |
|---|---|
|
relationship
Required
|
Metadata defining the many-to-many relationship. |
|
solution
Required
|
Optional solution unique name to add relationship to. |
Keyword-Only Parameters
| Name | Description |
|---|---|
|
solution
|
Default value: None
|
Returns
| Type | Description |
|---|---|
|
Relationship metadata with |
Exceptions
| Type | Description |
|---|---|
|
If the Web API request fails. |
Examples
Create a many-to-many relationship: Employee <-> Project:
from PowerPlatform.Dataverse.models import (
ManyToManyRelationshipMetadata,
)
relationship = ManyToManyRelationshipMetadata(
schema_name="new_employee_project",
entity1_logical_name="new_employee",
entity2_logical_name="new_project",
)
result = client.tables.create_many_to_many_relationship(relationship)
print(f"Created: {result.relationship_schema_name}")
create_one_to_many_relationship
Create a one-to-many relationship between tables.
This operation creates both the relationship and the lookup attribute on the referencing table.
create_one_to_many_relationship(lookup: LookupAttributeMetadata, relationship: OneToManyRelationshipMetadata, *, solution: str | None = None) -> RelationshipInfo
Parameters
| Name | Description |
|---|---|
|
lookup
Required
|
Metadata defining the lookup attribute. |
|
relationship
Required
|
Metadata defining the relationship. |
|
solution
Required
|
Optional solution unique name to add relationship to. |
Keyword-Only Parameters
| Name | Description |
|---|---|
|
solution
|
Default value: None
|
Returns
| Type | Description |
|---|---|
|
Relationship metadata with |
Exceptions
| Type | Description |
|---|---|
|
If the Web API request fails. |
Examples
Create a one-to-many relationship: Department (1) -> Employee (N):
from PowerPlatform.Dataverse.models import (
LookupAttributeMetadata,
OneToManyRelationshipMetadata,
Label,
LocalizedLabel,
CascadeConfiguration,
)
from PowerPlatform.Dataverse.common.constants import (
CASCADE_BEHAVIOR_REMOVE_LINK,
)
lookup = LookupAttributeMetadata(
schema_name="new_DepartmentId",
display_name=Label(
localized_labels=[
LocalizedLabel(label="Department", language_code=1033)
]
),
)
relationship = OneToManyRelationshipMetadata(
schema_name="new_Department_Employee",
referenced_entity="new_department",
referencing_entity="new_employee",
referenced_attribute="new_departmentid",
cascade_configuration=CascadeConfiguration(
delete=CASCADE_BEHAVIOR_REMOVE_LINK,
),
)
result = client.tables.create_one_to_many_relationship(lookup, relationship)
print(f"Created lookup field: {result.lookup_schema_name}")
delete
Delete a custom table by schema name.
Warning
This operation is irreversible and will delete all records in the
table along with the table definition.
Example:
client.tables.delete("new_MyTestTable")
delete(table: str) -> None
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
Exceptions
| Type | Description |
|---|---|
|
If the table does not exist or deletion fails. |
delete_alternate_key
Delete an alternate key by its metadata ID.
Warning
Deleting an alternate key that is in use by upsert operations will
cause those operations to fail. This operation is irreversible.
Example:
client.tables.delete_alternate_key(
"new_Product",
"12345678-1234-1234-1234-123456789abc",
)
delete_alternate_key(table: str, key_id: str) -> None
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
|
key_id
Required
|
Metadata GUID of the alternate key to delete. |
Exceptions
| Type | Description |
|---|---|
|
If the table does not exist. |
|
|
If the Web API request fails. |
delete_relationship
Delete a relationship by its metadata ID.
Warning
Deleting a relationship also removes the associated lookup attribute
for one-to-many relationships. This operation is irreversible.
Example:
client.tables.delete_relationship(
"12345678-1234-1234-1234-123456789abc"
)
delete_relationship(relationship_id: str) -> None
Parameters
| Name | Description |
|---|---|
|
relationship_id
Required
|
The GUID of the relationship metadata. |
Exceptions
| Type | Description |
|---|---|
|
If the Web API request fails. |
get
Get basic metadata for a table if it exists.
Example:
info = client.tables.get("new_MyTestTable")
if info:
print(f"Logical name: {info['table_logical_name']}")
print(f"Entity set: {info['entity_set_name']}")
get(table: str) -> TableInfo | None
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
Returns
| Type | Description |
|---|---|
|
Table metadata, or |
get_alternate_keys
List all alternate keys defined on a table.
get_alternate_keys(table: str) -> List[AlternateKeyInfo]
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
Returns
| Type | Description |
|---|---|
|
List of alternate key metadata objects. May be empty if no alternate keys are defined. |
Exceptions
| Type | Description |
|---|---|
|
If the table does not exist. |
|
|
If the Web API request fails. |
Examples
List alternate keys and print their status:
keys = client.tables.get_alternate_keys("new_Product")
for key in keys:
print(f"{key.schema_name}: {key.status}")
get_relationship
Retrieve relationship metadata by schema name.
Example:
rel = client.tables.get_relationship("new_Department_Employee")
if rel:
print(f"Found: {rel.relationship_schema_name}")
get_relationship(schema_name: str) -> RelationshipInfo | None
Parameters
| Name | Description |
|---|---|
|
schema_name
Required
|
The schema name of the relationship. |
Returns
| Type | Description |
|---|---|
|
Relationship metadata, or |
Exceptions
| Type | Description |
|---|---|
|
If the Web API request fails. |
list
List all non-private tables in the Dataverse environment.
By default returns every table where IsPrivate eq false. Supply
an optional OData $filter expression to further narrow the results.
The expression is combined with the default IsPrivate eq false
clause using and.
Example:
# List all non-private tables
tables = client.tables.list()
for table in tables:
print(table["LogicalName"])
# List only tables whose schema name starts with "new_"
custom_tables = client.tables.list(
filter="startswith(SchemaName, 'new_')"
)
# List tables with only specific properties
tables = client.tables.list(
select=["LogicalName", "SchemaName", "EntitySetName"]
)
list(*, filter: str | None = None, select: List[str] | None = None) -> List[Dict[str, Any]]
Parameters
| Name | Description |
|---|---|
|
filter
Required
|
Optional OData |
|
select
Required
|
Optional list of property names to include in the
response (projected via the OData |
Keyword-Only Parameters
| Name | Description |
|---|---|
|
filter
|
Default value: None
|
|
select
|
Default value: None
|
Returns
| Type | Description |
|---|---|
|
List of EntityDefinition metadata dictionaries. |
list_columns
List all attribute (column) definitions for a table.
Example:
# List all columns on the account table
columns = client.tables.list_columns("account")
for col in columns:
print(f"{col['LogicalName']} ({col.get('AttributeType')})")
# List only specific properties
columns = client.tables.list_columns(
"account",
select=["LogicalName", "SchemaName", "AttributeType"],
)
# Filter to only string attributes
columns = client.tables.list_columns(
"account",
filter="AttributeType eq 'String'",
)
list_columns(table: str, *, select: List[str] | None = None, filter: str | None = None) -> List[Dict[str, Any]]
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
|
select
Required
|
Optional list of property names to project via
|
|
filter
Required
|
Optional OData |
Keyword-Only Parameters
| Name | Description |
|---|---|
|
select
|
Default value: None
|
|
filter
|
Default value: None
|
Returns
| Type | Description |
|---|---|
|
List of raw attribute metadata dictionaries. |
Exceptions
| Type | Description |
|---|---|
|
If the table is not found. |
|
|
If the Web API request fails. |
list_relationships
List all relationship definitions in the environment.
Example:
# List all relationships
rels = client.tables.list_relationships()
for rel in rels:
print(f"{rel['SchemaName']} ({rel.get('@odata.type')})")
# Filter by type
one_to_many = client.tables.list_relationships(
filter="RelationshipType eq Microsoft.Dynamics.CRM.RelationshipType'OneToManyRelationship'"
)
# Select specific properties
rels = client.tables.list_relationships(
select=["SchemaName", "ReferencedEntity", "ReferencingEntity"]
)
list_relationships(*, filter: str | None = None, select: List[str] | None = None) -> List[Dict[str, Any]]
Parameters
| Name | Description |
|---|---|
|
filter
Required
|
Optional OData |
|
select
Required
|
Optional list of property names to project via
|
Keyword-Only Parameters
| Name | Description |
|---|---|
|
filter
|
Default value: None
|
|
select
|
Default value: None
|
Returns
| Type | Description |
|---|---|
|
List of raw relationship metadata dictionaries. |
Exceptions
| Type | Description |
|---|---|
|
If the Web API request fails. |
list_table_relationships
List all relationships for a specific table.
Combines one-to-many, many-to-one, and many-to-many relationships
for the given table by querying
EntityDefinitions({id})/OneToManyRelationships,
EntityDefinitions({id})/ManyToOneRelationships, and
EntityDefinitions({id})/ManyToManyRelationships.
Example:
# List all relationships for the account table
rels = client.tables.list_table_relationships("account")
for rel in rels:
print(f"{rel['SchemaName']} -> {rel.get('@odata.type')}")
list_table_relationships(table: str, *, filter: str | None = None, select: List[str] | None = None) -> List[Dict[str, Any]]
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
|
filter
Required
|
Optional OData |
|
select
Required
|
Optional list of property names to project via
|
Keyword-Only Parameters
| Name | Description |
|---|---|
|
filter
|
Default value: None
|
|
select
|
Default value: None
|
Returns
| Type | Description |
|---|---|
|
Combined list of one-to-many, many-to-one, and many-to-many relationship metadata dictionaries. |
Exceptions
| Type | Description |
|---|---|
|
If the table is not found. |
|
|
If the Web API request fails. |
remove_columns
Remove one or more columns from a table.
Example:
removed = client.tables.remove_columns(
"new_MyTestTable",
["new_Notes", "new_Active"],
)
print(removed) # ['new_Notes', 'new_Active']
remove_columns(table: str, columns: str | List[str]) -> List[str]
Parameters
| Name | Description |
|---|---|
|
table
Required
|
Schema name of the table (e.g. |
|
columns
Required
|
Column schema name or list of column schema names to
remove. Must include the customization prefix (e.g.
|
Returns
| Type | Description |
|---|---|
|
Schema names of the columns that were removed. |
Exceptions
| Type | Description |
|---|---|
|
If the table or a specified column does not exist. |