Skip to content

Change tracking plugin records ID=undefined for bulk operations with IN clauseΒ #192

@cryzzer

Description

@cryzzer

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

  1. Set up CAP application with change tracking plugin enabled
  2. Create an entity with service exposure for change tracking
  3. Perform bulk UPDATE using WHERE ID IN [array]
  4. Check change tracking table entries
  5. Observe ID=undefined in 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 } });

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions