From 14bcc8364de6269bc0cb87e681f9a8bcd83eb0d0 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 16 Jan 2026 14:57:53 +1100 Subject: [PATCH 1/2] Preserve @odata keys when normalizing record keys --- src/PowerPlatform/Dataverse/data/_odata.py | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/PowerPlatform/Dataverse/data/_odata.py b/src/PowerPlatform/Dataverse/data/_odata.py index df78185..1d60ffc 100644 --- a/src/PowerPlatform/Dataverse/data/_odata.py +++ b/src/PowerPlatform/Dataverse/data/_odata.py @@ -92,14 +92,25 @@ def _normalize_cache_key(table_schema_name: str) -> str: @staticmethod def _lowercase_keys(record: Dict[str, Any]) -> Dict[str, Any]: - """Convert all dictionary keys to lowercase for case-insensitive column names. + """Normalize dictionary keys to lowercase for case-insensitive column names. Dataverse LogicalNames for attributes are stored lowercase, but users may provide PascalCase names (matching SchemaName). This normalizes the input. + This function lowercases all string keys except OData annotation keys, + which must remain case-sensitive. """ if not isinstance(record, dict): return record - return {k.lower() if isinstance(k, str) else k: v for k, v in record.items()} + + new_record = {} + + # Preserve OData annotation keys as they are case sensitive + for k, v in record.items(): + if isinstance(k, str) and "@odata" in k: + new_record[k] = v + else: + new_record[k.lower() if isinstance(k, str) else k] = v + return new_record @staticmethod def _lowercase_list(items: Optional[List[str]]) -> Optional[List[str]]: @@ -269,7 +280,7 @@ def _create(self, entity_set: str, table_schema_name: str, record: Dict[str, Any .. note:: Relies on ``OData-EntityId`` (canonical) or ``Location`` response header. No response body parsing is performed. Raises ``RuntimeError`` if neither header contains a GUID. """ - # Lowercase all keys to match Dataverse LogicalName expectations + # Lowercase Dataverse attribute keys; keep OData annotation keys unchanged record = self._lowercase_keys(record) record = self._convert_labels_to_ints(table_schema_name, record) url = f"{self.api}/{entity_set}" @@ -313,7 +324,7 @@ def _create_multiple(self, entity_set: str, table_schema_name: str, records: Lis logical_name = table_schema_name.lower() enriched: List[Dict[str, Any]] = [] for r in records: - # Lowercase all keys to match Dataverse LogicalName expectations + # Lowercase Dataverse attribute keys; keep OData annotation keys unchanged r = self._lowercase_keys(r) r = self._convert_labels_to_ints(table_schema_name, r) if "@odata.type" in r or not need_logical: @@ -506,7 +517,7 @@ def _update(self, table_schema_name: str, key: str, data: Dict[str, Any]) -> Non :return: ``None`` :rtype: ``None`` """ - # Lowercase all keys to match Dataverse LogicalName expectations + # Lowercase Dataverse attribute keys; keep OData annotation keys unchanged data = self._lowercase_keys(data) data = self._convert_labels_to_ints(table_schema_name, data) entity_set = self._entity_set_from_schema_name(table_schema_name) @@ -540,7 +551,7 @@ def _update_multiple(self, entity_set: str, table_schema_name: str, records: Lis logical_name = table_schema_name.lower() enriched: List[Dict[str, Any]] = [] for r in records: - # Lowercase all keys to match Dataverse LogicalName expectations + # Lowercase Dataverse attribute keys; keep OData annotation keys unchanged r = self._lowercase_keys(r) r = self._convert_labels_to_ints(table_schema_name, r) if "@odata.type" in r or not need_logical: From 209675faa6b3a6b35dea83fdbb91d27062eeebc4 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 16 Jan 2026 17:26:26 +1100 Subject: [PATCH 2/2] Update src/PowerPlatform/Dataverse/data/_odata.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/PowerPlatform/Dataverse/data/_odata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerPlatform/Dataverse/data/_odata.py b/src/PowerPlatform/Dataverse/data/_odata.py index 1d60ffc..fee05a9 100644 --- a/src/PowerPlatform/Dataverse/data/_odata.py +++ b/src/PowerPlatform/Dataverse/data/_odata.py @@ -106,7 +106,7 @@ def _lowercase_keys(record: Dict[str, Any]) -> Dict[str, Any]: # Preserve OData annotation keys as they are case sensitive for k, v in record.items(): - if isinstance(k, str) and "@odata" in k: + if isinstance(k, str) and "@odata" in k.lower(): new_record[k] = v else: new_record[k.lower() if isinstance(k, str) else k] = v