-
Notifications
You must be signed in to change notification settings - Fork 15
Description
Problem Summary:
The CAP change tracking plugin fails to properly identify individual entities when performing bulk UPDATE or INSERT operations using the IN clause. Instead of recording the actual entity IDs, it logs ID=undefined in the change tracking table, making it impossible to trace which specific entities were modified.
Issue Details:
Expected Behavior: When updating multiple entities with a bulk operation, each affected entity should be individually tracked with its actual ID in the change log.
Actual Behavior: The change tracking plugin cannot determine individual entity IDs from bulk operations and records ID=undefined for all affected entities.
Code Example:
export class ProductRepository {
public async updateProductsStatus(
productIDs: string[],
status: string,
approverUserId?: string
): Promise<void> {
const { Product } = await ServiceHelper.getServiceEntities();
// This bulk operation causes ID=undefined in change tracking
await UPDATE(Product)
.set({
status_code: status,
lastModifiedBy: approverUserId,
})
.where({
ID: { IN: productIDs }, // Bulk update with IN clause
});
}
// Single entity update - works correctly
public async updateProductStatus(
productID: string,
status: string,
approverUserId?: string
): Promise<void> {
const { Product } = await ServiceHelper.getServiceEntities();
await UPDATE(Product)
.set({
status_code: status,
lastModifiedBy: approverUserId,
})
.where({ ID: productID }); // Single entity - works fine
}
}Change Log Output:
| ID | KEYS | ATTRIBUTE | VALUECHANGEDFROM | VALUECHANGEDTO | ENTITYID | ENTITY | PARENTENTITYID | PARENTKEY | SERVICEENTITYPATH | MODIFICATION | VALUEDATATYPE | CHANGELOGID |
|---------------------------------------|---------------|------------------|------------------|----------------|----------------------|---------------------|----------------|-----------|-------------------|--------------|---------------|------------|
| 0f0a0b0c-1d2e-3f40-5a6b-7c8d9e0f1a2b | ID=undefined | govStatus_ID | | ACTIVE | com.example.Product | MyService.Product | | | MyService.Product | create | cds.String | tx_10001 |
| 1a2b3c4d-5e6f-7081-92a3-b4c5d6e7f809 | ID=undefined | lastApprover_ID | | USER001 | com.example.Product | MyService.Product | | | MyService.Product | create | cds.String | tx_10002 |
| 2b3c4d5e-6f70-8192-a3b4-c5d6e7f8091a | ID=undefined | govStatus_ID | | ACTIVE | com.example.Product | MyService.Product | | | MyService.Product | create | cds.String | tx_10003 |
Comparison with Working Single-Entity Operations:
| ID | KEYS | ATTRIBUTE | VALUECHANGEDFROM | VALUECHANGEDTO | ENTITYID | ENTITY | PARENTENTITYID | PARENTKEY | SERVICEENTITYPATH | MODIFICATION | VALUEDATATYPE | CHANGELOGID |
|---------------------------------------|----------------------------------------------|--------------|------------------|----------------|----------------------|---------------------|----------------|-------------------------------------|-------------------|--------------|---------------|------------|
| d4e5f6g7-h8i9-0123-defg-4567890abcde | ID=550e8400-e29b-41d4-a716-446655440000 | status_code | DRAFT | ACTIVE | com.example.Product | MyService.Product | | 941fee5a-c752-40eb-a46a-b265a93fe9f7 | MyService.Product | update | cds.String | tx_12348 |
Impact:
- Audit Trail Broken: Unable to determine which specific entities were modified
- Compliance Issues: Change tracking requirements cannot be satisfied for bulk operations
- Debugging Difficulties: Troubleshooting data changes becomes nearly impossible
- Inconsistent Behavior: Single-entity operations work correctly while bulk operations fail
Environment:
CAP Version: "@sap/cds": "^8.3.1"
Change Tracking Plugin Version: "@cap-js/change-tracking": "^1.0.8"
Database: Tested with SQLite and SAP HANA
Reproduction Steps
- Set up CAP application with change tracking plugin enabled
- Create an entity with service exposure for change tracking
- Perform bulk
UPDATEusingWHERE ID IN [array] - Check change tracking table entries
- Observe
ID=undefinedin the logged changes
Minimal Example:
Entity Definition:
entity Products {
key ID: UUID;
name: String;
status_code: String;
lastModifiedBy: String;
}Service Definition:
service MyService {
entity Product as projection on db.Products;
}Test Data:
const productIds = [
'550e8400-e29b-41d4-a716-446655440000',
'6ba7b810-9dad-11d1-80b4-00c04fd430c8',
'6ba7b811-9dad-11d1-80b4-00c04fd430c9'
];
// This will cause ID=undefined in change tracking
await UPDATE(Product)
.set({ status_code: 'ACTIVE' })
.where({ ID: { IN: productIds } });